diff --git a/barbican/common/policies/acls.py b/barbican/common/policies/acls.py
index b98dcb8ec..64f8fd703 100644
--- a/barbican/common/policies/acls.py
+++ b/barbican/common/policies/acls.py
@@ -16,11 +16,24 @@ from oslo_policy import policy
 #                  - secret_acls:delete, secret_acls:put_patch
 #                  - container_acls:delete container_acls:put_patch
 
+_MEMBER = 'role:member'
+_ADMIN = 'role:admin'
+_SECRET_MEMBER = f"{_MEMBER} and project_id:%(target.secret.project_id)s"
+_SECRET_ADMIN = f"{_ADMIN} and project_id:%(target.secret.project_id)s"
+_SECRET_CREATOR = "user_id:%(target.secret.creator_id)s"
+_SECRET_IS_NOT_PRIVATE = "True:%(target.secret.read_project_access)s"
+_CONTAINER_MEMBER = f"{_MEMBER} and project_id:%(target.container.project_id)s"
+_CONTAINER_ADMIN = f"{_ADMIN} and project_id:%(target.container.project_id)s"
+_CONTAINER_CREATOR = "user_id:%(target.container.creator_id)s"
+_CONTAINER_IS_NOT_PRIVATE = "True:%(target.container.read_project_access)s"
+
 rules = [
     policy.DocumentedRuleDefault(
         name='secret_acls:get',
-        check_str='rule:all_but_audit and rule:secret_project_match',
-        scope_types=[],
+        check_str='(rule:all_but_audit and rule:secret_project_match) or ' +
+                  f"({_SECRET_MEMBER} and ({_SECRET_CREATOR} or " +
+                  f"{_SECRET_IS_NOT_PRIVATE})) or {_SECRET_ADMIN}",
+        scope_types=['project'],
         description='Retrieve the ACL settings for a given secret.'
                     'If no ACL is defined for that secret, then Default ACL '
                     'is returned.',
@@ -33,8 +46,10 @@ rules = [
     ),
     policy.DocumentedRuleDefault(
         name='secret_acls:delete',
-        check_str='rule:secret_project_admin or rule:secret_project_creator',
-        scope_types=[],
+        check_str='rule:secret_project_admin or rule:secret_project_creator' +
+                  f" or ({_SECRET_MEMBER} and ({_SECRET_CREATOR} or " +
+                  f"{_SECRET_IS_NOT_PRIVATE})) or {_SECRET_ADMIN}",
+        scope_types=['project'],
         description='Delete the ACL settings for a given secret.',
         operations=[
             {
@@ -45,8 +60,10 @@ rules = [
     ),
     policy.DocumentedRuleDefault(
         name='secret_acls:put_patch',
-        check_str='rule:secret_project_admin or rule:secret_project_creator',
-        scope_types=[],
+        check_str='rule:secret_project_admin or rule:secret_project_creator' +
+                  f" or ({_SECRET_MEMBER} and ({_SECRET_CREATOR} or " +
+                  f"{_SECRET_IS_NOT_PRIVATE})) or {_SECRET_ADMIN}",
+        scope_types=['project'],
         description='Create new, replaces, or updates existing ACL for a ' +
                     'given secret.',
         operations=[
@@ -62,8 +79,10 @@ rules = [
     ),
     policy.DocumentedRuleDefault(
         name='container_acls:get',
-        check_str='rule:all_but_audit and rule:container_project_match',
-        scope_types=[],
+        check_str='(rule:all_but_audit and rule:container_project_match) or ' +
+                  f"({_CONTAINER_MEMBER} and ({_CONTAINER_CREATOR} or " +
+                  f"{_CONTAINER_IS_NOT_PRIVATE})) or {_CONTAINER_ADMIN}",
+        scope_types=['project'],
         description='Retrieve the ACL settings for a given container.',
         operations=[
             {
@@ -75,8 +94,10 @@ rules = [
     policy.DocumentedRuleDefault(
         name='container_acls:delete',
         check_str='rule:container_project_admin or ' +
-                  'rule:container_project_creator',
-        scope_types=[],
+                  'rule:container_project_creator or ' +
+                  f"({_CONTAINER_MEMBER} and ({_CONTAINER_CREATOR} or " +
+                  f"{_CONTAINER_IS_NOT_PRIVATE})) or {_CONTAINER_ADMIN}",
+        scope_types=['project'],
         description='Delete ACL for a given container. No content is returned '
                     'in the case of successful deletion.',
         operations=[
@@ -89,8 +110,10 @@ rules = [
     policy.DocumentedRuleDefault(
         name='container_acls:put_patch',
         check_str='rule:container_project_admin or ' +
-                  'rule:container_project_creator',
-        scope_types=[],
+                  'rule:container_project_creator or ' +
+                  f"({_CONTAINER_MEMBER} and ({_CONTAINER_CREATOR} or " +
+                  f"{_CONTAINER_IS_NOT_PRIVATE})) or {_CONTAINER_ADMIN}",
+        scope_types=['project'],
         description='Create new or replaces existing ACL for a given '
                     'container.',
         operations=[
diff --git a/releasenotes/notes/secure-rbac-acl-policy-b534614ee7190108.yaml b/releasenotes/notes/secure-rbac-acl-policy-b534614ee7190108.yaml
new file mode 100644
index 000000000..4540d3c20
--- /dev/null
+++ b/releasenotes/notes/secure-rbac-acl-policy-b534614ee7190108.yaml
@@ -0,0 +1,15 @@
+---
+features:
+  - |
+    Implement secure-rbac policy for ACLs.
+security:
+  - |
+    The new secure-rbac policy does not allow listing ACLs for private secrets
+    or private containers.  This is a change from the previous policy which
+    allowed listing ACLs of private secrets or private containers by users with
+    some role assignments on the project.  The previous policy is deprecated,
+    but it will continue to be used until it is removed in a future release.
+  - |
+    The new secure-rbac policy allows ACLs to be modified or deleted by members
+    of a project.  This is a change from the previous policy which only allowed
+    these operations by the project admin or the secret or container creators.