diff --git a/public/recovery.te b/public/recovery.te
index a61c8e94f9cf6cce52458d27b5a60272c00377a9..1ec19c5ada5299a37cb4289f3746d3efd74b8795 100644
--- a/public/recovery.te
+++ b/public/recovery.te
@@ -9,7 +9,8 @@ type recovery, domain, domain_deprecated;
 recovery_only(`
   # Allow recovery to perform an update as update_engine would do.
   typeattribute recovery update_engine_common;
-  hal_client_domain(recovery, hal_bootctl)
+  # Recovery can only use HALs in passthrough mode
+  passthrough_hal_client_domain(recovery, hal_bootctl)
 
   allow recovery self:capability { chown dac_override fowner fsetid setfcap setuid setgid sys_admin sys_tty_config };
 
diff --git a/public/te_macros b/public/te_macros
index bc5da60372259b7a168c6a0b648b5a7188a39433..97dd948fce5583a36de4c71efd620223d4610bf6 100644
--- a/public/te_macros
+++ b/public/te_macros
@@ -203,6 +203,22 @@ typeattribute $1 $2;
 allow $2 system_file:dir r_dir_perms;
 ')
 
+#####################################
+# passthrough_hal_client_domain(domain, hal_type)
+# Allow a base set of permissions required for a domain to be a
+# client of a passthrough HAL of the specified type.
+#
+# For example, make some_domain a client of passthrough Foo HAL:
+#   passthrough_hal_client_domain(some_domain, hal_foo)
+#
+define(`passthrough_hal_client_domain', `
+typeattribute $1 halclientdomain;
+typeattribute $1 $2_client;
+typeattribute $1 $2;
+# Find passthrough HAL implementations
+allow $2 system_file:dir r_dir_perms;
+')
+
 #####################################
 # unix_socket_connect(clientdomain, socket, serverdomain)
 # Allow a local socket connection from clientdomain via