diff --git a/domain.te b/domain.te
index 5ed9dc9de9ca87d13e95333d162014d73a969725..93981727f2cab99068a08f5bc25fc668ee2a7043 100644
--- a/domain.te
+++ b/domain.te
@@ -398,6 +398,7 @@ neverallow {
   -postinstall_dexopt
   -cppreopts
   -dex2oat
+  -otapreopt_slot
 } dalvikcache_data_file:file no_w_file_perms;
 
 neverallow {
@@ -408,6 +409,7 @@ neverallow {
   -cppreopts
   -dex2oat
   -zygote
+  -otapreopt_slot
 } dalvikcache_data_file:dir no_w_dir_perms;
 
 # Only system_server should be able to send commands via the zygote socket
diff --git a/file_contexts b/file_contexts
index 719c3d9e714f9b66e000c76d750f33d062d5f484..ed8c5e1c8f7080b26102aa83d0c7e32d6d508560 100644
--- a/file_contexts
+++ b/file_contexts
@@ -172,6 +172,7 @@
 /system/bin/mdnsd	u:object_r:mdnsd_exec:s0
 /system/bin/installd	u:object_r:installd_exec:s0
 /system/bin/otapreopt_chroot   u:object_r:otapreopt_chroot_exec:s0
+/system/bin/otapreopt_slot   u:object_r:otapreopt_slot_exec:s0
 /system/bin/keystore	u:object_r:keystore_exec:s0
 /system/bin/fingerprintd u:object_r:fingerprintd_exec:s0
 /system/bin/gatekeeperd u:object_r:gatekeeperd_exec:s0
diff --git a/otapreopt_slot.te b/otapreopt_slot.te
new file mode 100644
index 0000000000000000000000000000000000000000..b68b399d72da09f4f03377f0f502b2e094da9c87
--- /dev/null
+++ b/otapreopt_slot.te
@@ -0,0 +1,27 @@
+# otapreopt_slot
+#
+# This command set moves the artifact corresponding to the current slot
+# from /data/ota to /data/dalvik-cache.
+
+type otapreopt_slot, domain, mlstrustedsubject;
+type otapreopt_slot_exec, exec_type, file_type;
+
+# Technically not a daemon but we do want the transition from init domain to
+# cppreopts to occur.
+init_daemon_domain(otapreopt_slot)
+
+# The otapreopt_slot renames the OTA dalvik-cache to the regular dalvik-cache, and cleans up
+# the directory afterwards.
+allow otapreopt_slot ota_data_file:dir { rw_dir_perms rename reparent rmdir };
+
+# Delete old content of the dalvik-cache.
+allow otapreopt_slot dalvikcache_data_file:dir { add_name getattr open read remove_name rmdir search write };
+allow otapreopt_slot dalvikcache_data_file:file { getattr unlink };
+allow otapreopt_slot dalvikcache_data_file:lnk_file { getattr read unlink };
+
+# Allow cppreopts to execute itself using #!/system/bin/sh
+allow otapreopt_slot shell_exec:file rx_file_perms;
+
+# Allow running the mv and rm/rmdir commands using otapreopt_slot  permissions.
+# Needed so we can move artifacts into /data/dalvik-cache/dalvik-cache.
+allow otapreopt_slot toolbox_exec:file rx_file_perms;
diff --git a/zygote.te b/zygote.te
index 41b8c070b41a219d2c4f082eacdd76bed3474459..9ce5a4e9d45deed85c2f33da975db0ba340d6bcb 100644
--- a/zygote.te
+++ b/zygote.te
@@ -88,31 +88,6 @@ userdebug_or_eng(`
 allow zygote ion_device:chr_file r_file_perms;
 allow zygote tmpfs:dir r_dir_perms;
 
-###
-### A/B OTA
-###
-
-# The zygote is responsible for detecting A/B OTA artifacts and moving them into
-# the actual dalvik-cache.
-
-# Allow zygote access to files in /data/ota.
-# This includes reading symlinks in /data/ota/dalvik-cache. This is required for PIC mode boot
-# images, where the oat file is symlinked to the original file in /system.
-r_dir_file(zygote, ota_data_file)
-
-# The zygote renames the OTA dalvik-cache to the regular dalvik-cache.
-allow zygote ota_data_file:dir { rw_dir_perms rename reparent };
-
-# And needs to relabel the entries, so as to have the dalvikcache_data_file label.
-allow zygote ota_data_file:{ dir file lnk_file } relabelfrom;
-allow zygote dalvikcache_data_file:{ dir file lnk_file } relabelto;
-
-# The zygote also cleans up the now-empty dalvik-cache directory after an OTA.
-# In case something goes wrong in relabelling, we also need to be able to delete the files that
-# have already been moved.
-allow zygote ota_data_file:dir rmdir;
-allow zygote ota_data_file:{ file lnk_file } unlink;
-
 ###
 ### neverallow rules
 ###