diff --git a/private/audioserver.te b/private/audioserver.te
index 88007aaa548a3dac53cf4c209e37dcab9d0ce0f6..17abd837d7c4210aa95e02fe02ea31ba86513e38 100644
--- a/private/audioserver.te
+++ b/private/audioserver.te
@@ -10,12 +10,8 @@ binder_call(audioserver, binderservicedomain)
 binder_call(audioserver, appdomain)
 binder_service(audioserver)
 
-hwbinder_use(audioserver)
-binder_call(audioserver, hal_audio)
-hwallocator_use(audioserver)
+hal_client_domain(audioserver, hal_audio)
 
-r_dir_file(audioserver, proc)
-allow audioserver ion_device:chr_file r_file_perms;
 allow audioserver system_file:dir r_dir_perms;
 
 userdebug_or_eng(`
@@ -28,9 +24,6 @@ userdebug_or_eng(`
   allow audioserver self:process ptrace;
 ')
 
-allow audioserver audio_device:dir r_dir_perms;
-allow audioserver audio_device:chr_file rw_file_perms;
-
 add_service(audioserver, audioserver_service)
 allow audioserver appops_service:service_manager find;
 allow audioserver batterystats_service:service_manager find;
@@ -42,10 +35,6 @@ allow audioserver scheduling_policy_service:service_manager find;
 allow audioserver audio_data_file:dir ra_dir_perms;
 allow audioserver audio_data_file:file create_file_perms;
 
-# Needed on some devices for playing audio on paired BT device,
-# but seems appropriate for all devices.
-unix_socket_connect(audioserver, bluetooth, bluetooth)
-
 ###
 ### neverallow rules
 ###
diff --git a/private/halclientdomain.te b/private/halclientdomain.te
new file mode 100644
index 0000000000000000000000000000000000000000..aa224ec04ff86fe5d7f5f4db06385f3400a48d22
--- /dev/null
+++ b/private/halclientdomain.te
@@ -0,0 +1,7 @@
+###
+### Rules for all domains which are clients of a HAL
+###
+
+# Find out whether a HAL in passthrough/in-process mode or
+# binderized/out-of-process mode
+hwbinder_use(halclientdomain)
diff --git a/private/haldomain.te b/private/haldomain.te
deleted file mode 100644
index 2700940ec156aceefeb70f91a3cd3565a69637e9..0000000000000000000000000000000000000000
--- a/private/haldomain.te
+++ /dev/null
@@ -1,8 +0,0 @@
-###
-### Rules for all HAL implementations
-###
-
-hwbinder_use(haldomain)
-
-# find passthrough hals
-allow haldomain system_file:dir r_dir_perms;
diff --git a/private/halserverdomain.te b/private/halserverdomain.te
new file mode 100644
index 0000000000000000000000000000000000000000..7be8360a4dda64bb51b27d7adcd83106271e9895
--- /dev/null
+++ b/private/halserverdomain.te
@@ -0,0 +1,9 @@
+###
+### Rules for all domains which offer a HAL service over HwBinder
+###
+
+# Register the HAL service with hwservicemanager
+hwbinder_use(halserverdomain)
+
+# Find HAL implementations
+allow halserverdomain system_file:dir r_dir_perms;
diff --git a/public/attributes b/public/attributes
index d9212fc1c0a51b680f429622303af3532f5bffc6..e48f96f69ce7f61b0e375caa34b220ad82fb6273 100644
--- a/public/attributes
+++ b/public/attributes
@@ -117,11 +117,15 @@ attribute boot_control_hal;
 # recovery for A/B devices.
 attribute update_engine_common;
 
-# All domains used for HAL implementations
-attribute haldomain;
+# All HAL servers
+attribute halserverdomain;
+# All HAL clients
+attribute halclientdomain;
 
 # HALs
 attribute hal_audio;
+attribute hal_audio_client;
+attribute hal_audio_server;
 attribute hal_bluetooth;
 attribute hal_camera;
 attribute hal_configstore;
diff --git a/public/hal_audio.te b/public/hal_audio.te
index 15d0e414ac7fa78b29a54200798fada58ab4846d..1d27c81be7bc4dcec3ea3a4250176e39deef729b 100644
--- a/public/hal_audio.te
+++ b/public/hal_audio.te
@@ -1,7 +1,10 @@
-binder_use(hal_audio)
-binder_call(hal_audio, audioserver)
-binder_call(hal_audio, system_server)
-hwallocator_use(hal_audio)
+# HwBinder IPC from client to server, and callbacks
+binder_call(hal_audio_client, hal_audio_server)
+binder_call(hal_audio_server, hal_audio_client)
+
+# Both client and the server need to use hwallocator
+hwallocator_use(hal_audio_client)
+hwallocator_use(hal_audio_server)
 
 allow hal_audio ion_device:chr_file r_file_perms;
 
@@ -17,8 +20,6 @@ r_dir_file(hal_audio, proc)
 allow hal_audio audio_device:dir r_dir_perms;
 allow hal_audio audio_device:chr_file rw_file_perms;
 
-allow hal_audio scheduling_policy_service:service_manager find;
-
 # Needed on some devices for playing audio on paired BT device,
 # but seems appropriate for all devices.
 unix_socket_connect(hal_audio, bluetooth, bluetooth)
@@ -27,10 +28,9 @@ unix_socket_connect(hal_audio, bluetooth, bluetooth)
 ### neverallow rules
 ###
 
-# hal_audio should never execute any executable without
-# a domain transition
+# Should never execute any executable without a domain transition
 neverallow hal_audio { file_type fs_type }:file execute_no_trans;
 
-# hal_audio should never need network access.
+# Should never need network access.
 # Disallow network sockets.
 neverallow hal_audio domain:{ tcp_socket udp_socket rawip_socket } *;
diff --git a/public/te_macros b/public/te_macros
index 4e334275f01841bbb178312c130f39db971ad7ef..a98ba7ed1c8f64123918cc86288578814fbd0364 100644
--- a/public/te_macros
+++ b/public/te_macros
@@ -148,6 +148,7 @@ define(`bluetooth_domain', `
 typeattribute $1 bluetoothdomain;
 ')
 
+# TODO: Remove hal_impl_domain once all uses have been switched to hal_server_domain.
 #####################################
 # hal_impl_domain(domain[, hal_type_attr])
 # Allow a base set of permissions required for a domain to host a
@@ -163,10 +164,46 @@ typeattribute $1 bluetoothdomain;
 #   hal_impl_domain(hal_foo_default, hal_foo)
 #
 define(`hal_impl_domain', `
-typeattribute $1 haldomain;
+print(`deprecated: hal_impl_domain($1, $2) Please use hal_server_domain($1, $2) instead.');
+typeattribute $1 halserverdomain;
 ifelse($2, `', `', `typeattribute $1 $2;')
 ')
 
+#####################################
+# hal_server_domain(domain, hal_type)
+# Allow a base set of permissions required for a domain to offer a
+# HAL implementation of the specified type over HwBinder.
+#
+# For example, default implementation of Foo HAL:
+#   type hal_foo_default, domain;
+#   hal_server_domain(hal_foo_default, hal_foo)
+#
+define(`hal_server_domain', `
+typeattribute $1 halserverdomain;
+typeattribute $1 $2_server;
+typeattribute $1 $2;
+')
+
+#####################################
+# hal_client_domain(domain, hal_type)
+# Allow a base set of permissions required for a domain to be a
+# client of a HAL of the specified type.
+#
+# For example, make some_domain a client of Foo HAL:
+#   hal_client_domain(some_domain, hal_foo)
+#
+define(`hal_client_domain', `
+typeattribute $1 halclientdomain;
+typeattribute $1 $2_client;
+
+# TODO(b/34170079): Make the inclusion of the rules below conditional,
+# once we know at build time whether a HAL is going to run in
+# passthrough or binderized mode.
+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
diff --git a/vendor/hal_audio_default.te b/vendor/hal_audio_default.te
index 93ffd8e51ef0464f46d0d7896abf7e0a63ad26d3..4811f4da386d785358bfd10c028bef0819a84faa 100644
--- a/vendor/hal_audio_default.te
+++ b/vendor/hal_audio_default.te
@@ -1,5 +1,5 @@
 type hal_audio_default, domain;
-hal_impl_domain(hal_audio_default, hal_audio)
+hal_server_domain(hal_audio_default, hal_audio)
 
 type hal_audio_default_exec, exec_type, file_type;
 init_daemon_domain(hal_audio_default)