diff --git a/src/api/client_server/push.rs b/src/api/client_server/push.rs
index b0441384..ab7c686f 100644
--- a/src/api/client_server/push.rs
+++ b/src/api/client_server/push.rs
@@ -5,11 +5,11 @@ use ruma::{
         push::{
             delete_pushrule, get_pushers, get_pushrule, get_pushrule_actions, get_pushrule_enabled,
             get_pushrules_all, set_pusher, set_pushrule, set_pushrule_actions,
-            set_pushrule_enabled, RuleKind, RuleScope,
+            set_pushrule_enabled, RuleScope,
         },
     },
     events::{push_rules::PushRulesEvent, GlobalAccountDataEventType},
-    push::{ConditionalPushRuleInit, NewPushRule, PatternedPushRuleInit, SimplePushRuleInit},
+    push::{InsertPushRuleError, RemovePushRuleError},
 };
 
 /// # `GET /_matrix/client/r0/pushrules`
@@ -65,30 +65,10 @@ pub async fn get_pushrule_route(
         .map_err(|_| Error::bad_database("Invalid account data event in db."))?
         .content;
 
-    let global = account_data.global;
-    let rule = match body.kind {
-        RuleKind::Override => global
-            .override_
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.clone().into()),
-        RuleKind::Underride => global
-            .underride
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.clone().into()),
-        RuleKind::Sender => global
-            .sender
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.clone().into()),
-        RuleKind::Room => global
-            .room
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.clone().into()),
-        RuleKind::Content => global
-            .content
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.clone().into()),
-        _ => None,
-    };
+    let rule = account_data
+        .global
+        .get(body.kind.clone(), &body.rule_id)
+        .map(Into::into);
 
     if let Some(rule) = rule {
         Ok(get_pushrule::v3::Response { rule })
@@ -131,66 +111,36 @@ pub async fn set_pushrule_route(
     let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
         .map_err(|_| Error::bad_database("Invalid account data event in db."))?;
 
-    let global = &mut account_data.content.global;
-    match body.rule {
-        NewPushRule::Override(rule) => {
-            global.override_.replace(
-                ConditionalPushRuleInit {
-                    actions: rule.actions,
-                    default: false,
-                    enabled: true,
-                    rule_id: rule.rule_id,
-                    conditions: rule.conditions,
-                }
-                .into(),
-            );
-        }
-        NewPushRule::Underride(rule) => {
-            global.underride.replace(
-                ConditionalPushRuleInit {
-                    actions: rule.actions,
-                    default: false,
-                    enabled: true,
-                    rule_id: rule.rule_id,
-                    conditions: rule.conditions,
-                }
-                .into(),
-            );
-        }
-        NewPushRule::Sender(rule) => {
-            global.sender.replace(
-                SimplePushRuleInit {
-                    actions: rule.actions,
-                    default: false,
-                    enabled: true,
-                    rule_id: rule.rule_id,
-                }
-                .into(),
-            );
-        }
-        NewPushRule::Room(rule) => {
-            global.room.replace(
-                SimplePushRuleInit {
-                    actions: rule.actions,
-                    default: false,
-                    enabled: true,
-                    rule_id: rule.rule_id,
-                }
-                .into(),
-            );
-        }
-        NewPushRule::Content(rule) => {
-            global.content.replace(
-                PatternedPushRuleInit {
-                    actions: rule.actions,
-                    default: false,
-                    enabled: true,
-                    rule_id: rule.rule_id,
-                    pattern: rule.pattern,
-                }
-                .into(),
-            );
-        }
+    if let Err(error) = account_data.content.global.insert(
+        body.rule.clone(),
+        body.after.as_deref(),
+        body.before.as_deref(),
+    ) {
+        let err = match error {
+            InsertPushRuleError::ServerDefaultRuleId => Error::BadRequest(
+                ErrorKind::InvalidParam,
+                "Rule IDs starting with a dot are reserved for server-default rules.",
+            ),
+            InsertPushRuleError::InvalidRuleId => Error::BadRequest(
+                ErrorKind::InvalidParam,
+                "Rule ID containing invalid characters.",
+            ),
+            InsertPushRuleError::RelativeToServerDefaultRule => Error::BadRequest(
+                ErrorKind::InvalidParam,
+                "Can't place a push rule relatively to a server-default rule.",
+            ),
+            InsertPushRuleError::UnknownRuleId => Error::BadRequest(
+                ErrorKind::NotFound,
+                "The before or after rule could not be found.",
+            ),
+            InsertPushRuleError::BeforeHigherThanAfter => Error::BadRequest(
+                ErrorKind::InvalidParam,
+                "The before rule has a higher priority than the after rule.",
+            ),
+            _ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."),
+        };
+
+        return Err(err);
     }
 
     services().account_data.update(
@@ -235,29 +185,9 @@ pub async fn get_pushrule_actions_route(
         .content;
 
     let global = account_data.global;
-    let actions = match body.kind {
-        RuleKind::Override => global
-            .override_
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.actions.clone()),
-        RuleKind::Underride => global
-            .underride
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.actions.clone()),
-        RuleKind::Sender => global
-            .sender
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.actions.clone()),
-        RuleKind::Room => global
-            .room
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.actions.clone()),
-        RuleKind::Content => global
-            .content
-            .get(body.rule_id.as_str())
-            .map(|rule| rule.actions.clone()),
-        _ => None,
-    };
+    let actions = global
+        .get(body.kind.clone(), &body.rule_id)
+        .map(|rule| rule.actions().to_owned());
 
     Ok(get_pushrule_actions::v3::Response {
         actions: actions.unwrap_or_default(),
@@ -294,40 +224,17 @@ pub async fn set_pushrule_actions_route(
     let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
         .map_err(|_| Error::bad_database("Invalid account data event in db."))?;
 
-    let global = &mut account_data.content.global;
-    match body.kind {
-        RuleKind::Override => {
-            if let Some(mut rule) = global.override_.get(body.rule_id.as_str()).cloned() {
-                rule.actions = body.actions.clone();
-                global.override_.replace(rule);
-            }
-        }
-        RuleKind::Underride => {
-            if let Some(mut rule) = global.underride.get(body.rule_id.as_str()).cloned() {
-                rule.actions = body.actions.clone();
-                global.underride.replace(rule);
-            }
-        }
-        RuleKind::Sender => {
-            if let Some(mut rule) = global.sender.get(body.rule_id.as_str()).cloned() {
-                rule.actions = body.actions.clone();
-                global.sender.replace(rule);
-            }
-        }
-        RuleKind::Room => {
-            if let Some(mut rule) = global.room.get(body.rule_id.as_str()).cloned() {
-                rule.actions = body.actions.clone();
-                global.room.replace(rule);
-            }
-        }
-        RuleKind::Content => {
-            if let Some(mut rule) = global.content.get(body.rule_id.as_str()).cloned() {
-                rule.actions = body.actions.clone();
-                global.content.replace(rule);
-            }
-        }
-        _ => {}
-    };
+    if account_data
+        .content
+        .global
+        .set_actions(body.kind.clone(), &body.rule_id, body.actions.clone())
+        .is_err()
+    {
+        return Err(Error::BadRequest(
+            ErrorKind::NotFound,
+            "Push rule not found.",
+        ));
+    }
 
     services().account_data.update(
         None,
@@ -370,34 +277,10 @@ pub async fn get_pushrule_enabled_route(
         .map_err(|_| Error::bad_database("Invalid account data event in db."))?;
 
     let global = account_data.content.global;
-    let enabled = match body.kind {
-        RuleKind::Override => global
-            .override_
-            .iter()
-            .find(|rule| rule.rule_id == body.rule_id)
-            .map_or(false, |rule| rule.enabled),
-        RuleKind::Underride => global
-            .underride
-            .iter()
-            .find(|rule| rule.rule_id == body.rule_id)
-            .map_or(false, |rule| rule.enabled),
-        RuleKind::Sender => global
-            .sender
-            .iter()
-            .find(|rule| rule.rule_id == body.rule_id)
-            .map_or(false, |rule| rule.enabled),
-        RuleKind::Room => global
-            .room
-            .iter()
-            .find(|rule| rule.rule_id == body.rule_id)
-            .map_or(false, |rule| rule.enabled),
-        RuleKind::Content => global
-            .content
-            .iter()
-            .find(|rule| rule.rule_id == body.rule_id)
-            .map_or(false, |rule| rule.enabled),
-        _ => false,
-    };
+    let enabled = global
+        .get(body.kind.clone(), &body.rule_id)
+        .map(|r| r.enabled())
+        .unwrap_or_default();
 
     Ok(get_pushrule_enabled::v3::Response { enabled })
 }
@@ -432,44 +315,16 @@ pub async fn set_pushrule_enabled_route(
     let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
         .map_err(|_| Error::bad_database("Invalid account data event in db."))?;
 
-    let global = &mut account_data.content.global;
-    match body.kind {
-        RuleKind::Override => {
-            if let Some(mut rule) = global.override_.get(body.rule_id.as_str()).cloned() {
-                global.override_.remove(&rule);
-                rule.enabled = body.enabled;
-                global.override_.insert(rule);
-            }
-        }
-        RuleKind::Underride => {
-            if let Some(mut rule) = global.underride.get(body.rule_id.as_str()).cloned() {
-                global.underride.remove(&rule);
-                rule.enabled = body.enabled;
-                global.underride.insert(rule);
-            }
-        }
-        RuleKind::Sender => {
-            if let Some(mut rule) = global.sender.get(body.rule_id.as_str()).cloned() {
-                global.sender.remove(&rule);
-                rule.enabled = body.enabled;
-                global.sender.insert(rule);
-            }
-        }
-        RuleKind::Room => {
-            if let Some(mut rule) = global.room.get(body.rule_id.as_str()).cloned() {
-                global.room.remove(&rule);
-                rule.enabled = body.enabled;
-                global.room.insert(rule);
-            }
-        }
-        RuleKind::Content => {
-            if let Some(mut rule) = global.content.get(body.rule_id.as_str()).cloned() {
-                global.content.remove(&rule);
-                rule.enabled = body.enabled;
-                global.content.insert(rule);
-            }
-        }
-        _ => {}
+    if account_data
+        .content
+        .global
+        .set_enabled(body.kind.clone(), &body.rule_id, body.enabled)
+        .is_err()
+    {
+        return Err(Error::BadRequest(
+            ErrorKind::NotFound,
+            "Push rule not found.",
+        ));
     }
 
     services().account_data.update(
@@ -512,34 +367,23 @@ pub async fn delete_pushrule_route(
     let mut account_data = serde_json::from_str::<PushRulesEvent>(event.get())
         .map_err(|_| Error::bad_database("Invalid account data event in db."))?;
 
-    let global = &mut account_data.content.global;
-    match body.kind {
-        RuleKind::Override => {
-            if let Some(rule) = global.override_.get(body.rule_id.as_str()).cloned() {
-                global.override_.remove(&rule);
+    if let Err(error) = account_data
+        .content
+        .global
+        .remove(body.kind.clone(), &body.rule_id)
+    {
+        let err = match error {
+            RemovePushRuleError::ServerDefault => Error::BadRequest(
+                ErrorKind::InvalidParam,
+                "Cannot delete a server-default pushrule.",
+            ),
+            RemovePushRuleError::NotFound => {
+                Error::BadRequest(ErrorKind::NotFound, "Push rule not found.")
             }
-        }
-        RuleKind::Underride => {
-            if let Some(rule) = global.underride.get(body.rule_id.as_str()).cloned() {
-                global.underride.remove(&rule);
-            }
-        }
-        RuleKind::Sender => {
-            if let Some(rule) = global.sender.get(body.rule_id.as_str()).cloned() {
-                global.sender.remove(&rule);
-            }
-        }
-        RuleKind::Room => {
-            if let Some(rule) = global.room.get(body.rule_id.as_str()).cloned() {
-                global.room.remove(&rule);
-            }
-        }
-        RuleKind::Content => {
-            if let Some(rule) = global.content.get(body.rule_id.as_str()).cloned() {
-                global.content.remove(&rule);
-            }
-        }
-        _ => {}
+            _ => Error::BadRequest(ErrorKind::InvalidParam, "Invalid data."),
+        };
+
+        return Err(err);
     }
 
     services().account_data.update(