diff --git a/aleksis/core/mixins.py b/aleksis/core/mixins.py
index 8ba220c1610321971f6b7c96ca20b7ce65fe0d5b..c4ec43e40839d788b9fecfeedc12403c5892c0c5 100644
--- a/aleksis/core/mixins.py
+++ b/aleksis/core/mixins.py
@@ -7,8 +7,10 @@ from django.db.models import QuerySet
 from django.forms.models import ModelFormMetaclass, ModelForm
 
 from easyaudit.models import CRUDEvent
+from guardian.admin import GuardedModelAdmin
 from jsonstore.fields import JSONField, JSONFieldMixin
 from material.base import LayoutNode, Layout
+from rules.contrib.admin import ObjectPermissionsModelAdmin
 
 
 class CRUDMixin(models.Model):
@@ -226,3 +228,7 @@ class ExtensibleForm(ModelForm, metaclass=_ExtensibleFormMetaclass):
 
         cls.base_layout.append(node)
         cls.layout = Layout(*cls.base_layout)
+
+
+class BaseModelAdmin(GuardedModelAdmin, ObjectPermissionsModelAdmin):
+    pass
diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py
index cac277a711763ed431e3ccd213842151d1969213..94338cf8bcec2032251864bc09434767a6bf0307 100644
--- a/aleksis/core/settings.py
+++ b/aleksis/core/settings.py
@@ -188,7 +188,6 @@ AUTH_PASSWORD_VALIDATORS = [
 
 # Authentication backends are dynamically populated
 AUTHENTICATION_BACKENDS = []
-AUTHENTICATION_BACKENDS.append("rules.permissions.ObjectPermissionBackend")
 
 if _settings.get("ldap.uri", None):
     # LDAP dependencies are not necessarily installed, so import them here
@@ -568,5 +567,4 @@ GUARDIAN_RAISE_403 = True
 ANONYMOUS_USER_NAME = None
 
 # Append authentication backends
-AUTHENTICATION_BACKENDS.append("guardian.backends.ObjectPermissionBackend")
-#AUTHENTICATION_BACKENDS.append("rules.permissions.ObjectPermissionBackend")
+AUTHENTICATION_BACKENDS.append("rules.permissions.ObjectPermissionBackend")
diff --git a/aleksis/core/util/predicates.py b/aleksis/core/util/predicates.py
new file mode 100644
index 0000000000000000000000000000000000000000..7195cd45195effc014e36be78bc3117f1581ce31
--- /dev/null
+++ b/aleksis/core/util/predicates.py
@@ -0,0 +1,86 @@
+from django.contrib.auth.backends import ModelBackend
+from django.contrib.auth.models import User
+from django.db.models import Model
+from django.http import HttpRequest
+from guardian.backends import ObjectPermissionBackend
+from guardian.shortcuts import get_objects_for_user
+from rules import predicate
+
+from aleksis.core.util.core_helpers import has_person
+
+# 1. Global permissions (view all, add, change all, delete all)
+# 2. Object permissions (view, change, delete)
+# 3. Rules
+
+
+def permission_validator(request: HttpRequest, perm: str) -> bool:
+    """ Checks whether the request user has a permission """
+
+    if request.user:
+        return request.user.has_perm(perm)
+    return False
+
+
+def check_global_permission(user: User, perm: str) -> bool:
+    """ Checks whether a user has a global permission """
+
+    return ModelBackend().has_perm(user, perm)
+
+
+def check_object_permission(user: User, perm: str, obj: Model) -> bool:
+    """ Checks whether a user has a permission on a object """
+
+    return ObjectPermissionBackend().has_perm(user, perm, obj)
+
+
+def has_global_perm(perm: str):
+    """ Builds predicate which checks whether a user has a global permission """
+
+    name = "has_global_perm:{}".format(perm)
+
+    @predicate(name)
+    def fn(user: User) -> bool:
+        return check_global_permission(user, perm)
+
+    return fn
+
+
+def has_object_perm(perm: str):
+    """ Builds predicate which checks whether a user has a permission on a object """
+
+    name = "has_global_perm:{}".format(perm)
+
+    @predicate(name)
+    def fn(user: User, obj: Model) -> bool:
+        if not obj:
+            return False
+        return check_object_permission(user, perm, obj)
+
+    return fn
+
+
+def has_any_object(perm: str, klass):
+    """ Build predicate which checks whether a user has access to objects with the provided permission """
+
+    name = "has_any_object:{}".format(perm)
+
+    @predicate(name)
+    def fn(user: User) -> bool:
+        objs = get_objects_for_user(user, perm, klass)
+        return len(objs) > 0
+
+    return fn
+
+
+@predicate
+def has_person_predicate(user: User) -> bool:
+    """ Predicate which checks whether a user has a linked person """
+
+    return has_person(user)
+
+
+@predicate()
+def is_person(user: User, obj: Model) -> bool:
+    """ Predicate which checks if the provided object is the person linked to the user object """
+
+    return user.person == obj