diff --git a/domain.te b/domain.te
index 1d8576ae6403b36167686cb54d5f4e76eb23f05a..d04bdf0e8190a492ee8fc7a984425744a338e11c 100644
--- a/domain.te
+++ b/domain.te
@@ -384,6 +384,7 @@ neverallow {
   -postinstall_dexopt
   -cppreopts
   -dex2oat
+  -otapreopt_slot
 } dalvikcache_data_file:file no_w_file_perms;
 
 neverallow {
@@ -394,6 +395,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 6df6f6935222194a376f868bf5335f54c14faeeb..d5f919426dead9aad336c47b7351770c62c3ecf6 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 9e155efb6ac6e16a7b076f1be28070e29589e0ce..d35235e3876eb475127263426e3fa7daf0199643 100644
--- a/zygote.te
+++ b/zygote.te
@@ -79,31 +79,6 @@ userdebug_or_eng(`
   allow zygote method_trace_data_file:file { create w_file_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
 ###