diff --git a/aleksis/core/models.py b/aleksis/core/models.py
index 842b72ac5b9b3cef46fff392ddc12071b52d3d7c..1fa61d27804ee189058a111aecd784f16c0cf335 100644
--- a/aleksis/core/models.py
+++ b/aleksis/core/models.py
@@ -520,6 +520,9 @@ class GlobalPermissions(ExtensibleModel):
             ("manage_data", _("Can manage data")),
             ("impersonate", _("Can impersonate")),
             ("search", _("Can use search")),
+            ("change_site_preferences", _("Can change site preferences")),
+            ("change_person_preferences", _("Can change person preferences")),
+            ("change_group_preferences", _("Can change group preferences")),
         )
 
 
diff --git a/aleksis/core/rules.py b/aleksis/core/rules.py
index 9c83692220005180cd0af53e798e60c103b7ef18..2a0889262e349d0479f4d55f03e8941b5f274bb7 100644
--- a/aleksis/core/rules.py
+++ b/aleksis/core/rules.py
@@ -7,6 +7,7 @@ from .util.predicates import (
     has_any_object,
     is_current_person,
     has_object_perm,
+    is_group_owner,
 )
 
 
@@ -141,3 +142,21 @@ view_personal_details_predicate = has_person & (
     has_global_perm("core.view_personal_details") | has_object_perm("core.view_personal_details") | is_current_person
 )
 add_perm("core.view_personal_details", view_personal_details_predicate)
+
+# Change site preferences
+change_site_preferences = has_person & (
+    has_global_perm("core.change_site_preferences") | has_object_perm("core.change_site_preferences")
+)
+add_perm("core.change_site_preferences", change_site_preferences)
+
+# Change person preferences
+change_person_preferences = has_person & (
+    has_global_perm("core.change_person_preferences") | has_object_perm("core.change_person_preferences") | is_current_person
+)
+add_perm("core.change_person_preferences", change_person_preferences)
+
+# Change group preferences
+change_group_preferences = has_person & (
+    has_global_perm("core.change_group_preferences") | has_object_perm("core.change_group_preferences") | is_group_owner
+)
+add_perm("core.change_group_preferences", change_group_preferences)
diff --git a/aleksis/core/util/predicates.py b/aleksis/core/util/predicates.py
index 3fb1b64e98ee26f29b2b72014ccf66bc2c39e53d..4ea9226c313c2484dbb2d7cf65ac653176c67fa9 100644
--- a/aleksis/core/util/predicates.py
+++ b/aleksis/core/util/predicates.py
@@ -11,6 +11,7 @@ from .core_helpers import has_person as has_person_helper
 # 1. Global permissions (view all, add, change all, delete all)
 # 2. Object permissions (view, change, delete)
 # 3. Rules
+from ..models import Group
 
 
 def permission_validator(request: HttpRequest, perm: str) -> bool:
@@ -84,3 +85,11 @@ def is_current_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
+
+
+@predicate
+def is_group_owner(user: User, group: Group) -> bool:
+    """ Predicate which checks if the user is a owner of the provided group """
+
+    return group.owners.filter(owners=user.person).exists()
+
diff --git a/aleksis/core/views.py b/aleksis/core/views.py
index f5face969248b2d8762312d5b20e405967f813ae..45b8d36fa5f38572617c0e19bcbec8a0b2923777 100644
--- a/aleksis/core/views.py
+++ b/aleksis/core/views.py
@@ -386,6 +386,8 @@ def preferences(request: HttpRequest, registry_name: str = "person", pk: Optiona
         instance = request.site
         form_class = SitePreferenceForm
 
+        if not request.user.has_perm("core.change_site_preferences", instance):
+            raise PermissionDenied()
     elif registry_name == "person":
         registry = person_preferences_registry
         if pk:
@@ -394,11 +396,15 @@ def preferences(request: HttpRequest, registry_name: str = "person", pk: Optiona
             instance = request.user.person
         form_class = PersonPreferenceForm
 
+        if not request.user.has_perm("core.change_person_preferences", instance):
+            raise PermissionDenied()
     elif registry_name == "group":
         registry = group_preferences_registry
         instance = get_object_or_404(Group, pk=pk)
         form_class = GroupPreferenceForm
 
+        if not request.user.has_perm("core.change_group_preferences", instance):
+            raise PermissionDenied()
     else:
         return HttpResponseNotFound()