diff --git a/changelog.d/8007.feature b/changelog.d/8007.feature
new file mode 100644
index 0000000000..0ae4cc49af
--- /dev/null
+++ b/changelog.d/8007.feature
@@ -0,0 +1 @@
+[Poll] Synchronize polls push rules with message push rules
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleIds.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleIds.kt
index 4f35fb79c3..a3755f85b7 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleIds.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/RuleIds.kt
@@ -47,8 +47,36 @@ object RuleIds {
     const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message"
     const val RULE_ID_ENCRYPTED = ".m.rule.encrypted"
 
+    const val RULE_ID_POLL_START_ONE_TO_ONE = ".m.rule.poll_start_one_to_one"
+    const val RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE = ".org.matrix.msc3930.rule.poll_start_one_to_one"
+    const val RULE_ID_POLL_END_ONE_TO_ONE = ".m.rule.poll_end_one_to_one"
+    const val RULE_ID_POLL_END_ONE_TO_ONE_UNSTABLE = ".org.matrix.msc3930.rule.poll_end_one_to_one"
+
+    const val RULE_ID_POLL_START = ".m.rule.poll_start"
+    const val RULE_ID_POLL_START_UNSTABLE = ".org.matrix.msc3930.rule.poll_start"
+    const val RULE_ID_POLL_END = ".m.rule.poll_end"
+    const val RULE_ID_POLL_END_UNSTABLE = ".org.matrix.msc3930.rule.poll_end"
+
     // Not documented
     const val RULE_ID_FALLBACK = ".m.rule.fallback"
 
     const val RULE_ID_REACTION = ".m.rule.reaction"
+
+    fun getSyncedRules(ruleId: String): List<String> {
+        return when (ruleId) {
+            RULE_ID_ONE_TO_ONE_ROOM -> listOf(
+                    RULE_ID_POLL_START_ONE_TO_ONE,
+                    RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE,
+                    RULE_ID_POLL_END_ONE_TO_ONE,
+                    RULE_ID_POLL_END_ONE_TO_ONE_UNSTABLE,
+            )
+            RULE_ID_ALL_OTHER_MESSAGES_ROOMS -> listOf(
+                    RULE_ID_POLL_START,
+                    RULE_ID_POLL_START_UNSTABLE,
+                    RULE_ID_POLL_END,
+                    RULE_ID_POLL_END_UNSTABLE,
+            )
+            else -> emptyList()
+        }
+    }
 }
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt
index 9498ed002c..9287a7828d 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushrules/rest/RuleSet.kt
@@ -47,21 +47,14 @@ data class RuleSet(
      * @param ruleId a RULE_ID_XX value
      * @return the matched bing rule or null it doesn't exist.
      */
-    fun findDefaultRule(ruleId: String?): PushRuleAndKind? {
-        var result: PushRuleAndKind? = null
-        // sanity check
-        if (null != ruleId) {
-            if (RuleIds.RULE_ID_CONTAIN_USER_NAME == ruleId) {
-                result = findRule(content, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.CONTENT) }
-            } else {
-                // assume that the ruleId is unique.
-                result = findRule(override, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.OVERRIDE) }
-                if (null == result) {
-                    result = findRule(underride, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.UNDERRIDE) }
-                }
-            }
+    fun findDefaultRule(ruleId: String): PushRuleAndKind? {
+        return if (RuleIds.RULE_ID_CONTAIN_USER_NAME == ruleId) {
+            findRule(content, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.CONTENT) }
+        } else {
+            // assume that the ruleId is unique.
+            findRule(override, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.OVERRIDE) }
+                    ?: findRule(underride, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.UNDERRIDE) }
         }
-        return result
     }
 
     /**
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt
index 9fe93d8262..3dfac694ed 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt
@@ -57,6 +57,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
         val allEvents = (newJoinEvents + inviteEvents).filter { event ->
             when (event.type) {
                 in EventType.POLL_START.values,
+                in EventType.POLL_END.values,
                 in EventType.STATE_ROOM_BEACON_INFO.values,
                 EventType.MESSAGE,
                 EventType.REDACTION,
diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
index c2e2f9f695..35d8d0e896 100644
--- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
@@ -108,7 +108,8 @@ import im.vector.app.features.settings.ignored.IgnoredUsersViewModel
 import im.vector.app.features.settings.labs.VectorSettingsLabsViewModel
 import im.vector.app.features.settings.legals.LegalsViewModel
 import im.vector.app.features.settings.locale.LocalePickerViewModel
-import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceViewModel
+import im.vector.app.features.settings.notifications.VectorSettingsNotificationViewModel
+import im.vector.app.features.settings.notifications.VectorSettingsPushRuleNotificationViewModel
 import im.vector.app.features.settings.push.PushGatewaysViewModel
 import im.vector.app.features.settings.threepids.ThreePidsSettingsViewModel
 import im.vector.app.features.share.IncomingShareViewModel
@@ -690,9 +691,16 @@ interface MavericksViewModelModule {
 
     @Binds
     @IntoMap
-    @MavericksViewModelKey(VectorSettingsNotificationPreferenceViewModel::class)
+    @MavericksViewModelKey(VectorSettingsNotificationViewModel::class)
     fun vectorSettingsNotificationPreferenceViewModelFactory(
-            factory: VectorSettingsNotificationPreferenceViewModel.Factory
+            factory: VectorSettingsNotificationViewModel.Factory
+    ): MavericksAssistedViewModelFactory<*, *>
+
+    @Binds
+    @IntoMap
+    @MavericksViewModelKey(VectorSettingsPushRuleNotificationViewModel::class)
+    fun vectorSettingsPushRuleNotificationPreferenceViewModelFactory(
+            factory: VectorSettingsPushRuleNotificationViewModel.Factory
     ): MavericksAssistedViewModelFactory<*, *>
 
     @Binds
diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt
index a69958ef25..14a36d9922 100644
--- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt
+++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt
@@ -67,7 +67,7 @@ class NotifiableEventResolver @Inject constructor(
 ) {
 
     private val nonEncryptedNotifiableEventTypes: List<String> =
-            listOf(EventType.MESSAGE) + EventType.POLL_START.values + EventType.STATE_ROOM_BEACON_INFO.values
+            listOf(EventType.MESSAGE) + EventType.POLL_START.values + EventType.POLL_END.values + EventType.STATE_ROOM_BEACON_INFO.values
 
     suspend fun resolveEvent(event: Event, session: Session, isNoisy: Boolean): NotifiableEvent? {
         val roomID = event.roomId ?: return null
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt
index 4a9db49c67..33557fabef 100755
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt
@@ -32,7 +32,7 @@ import im.vector.app.databinding.ActivityVectorSettingsBinding
 import im.vector.app.features.discovery.DiscoverySettingsFragment
 import im.vector.app.features.navigation.SettingsActivityPayload
 import im.vector.app.features.settings.devices.VectorSettingsDevicesFragment
-import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment
+import im.vector.app.features.settings.notifications.VectorSettingsNotificationFragment
 import im.vector.app.features.settings.threepids.ThreePidsSettingsFragment
 import im.vector.lib.core.utils.compat.getParcelableExtraCompat
 import org.matrix.android.sdk.api.failure.GlobalError
@@ -92,7 +92,7 @@ class VectorSettingsActivity : VectorBaseActivity<ActivityVectorSettingsBinding>
                 }
                 SettingsActivityPayload.Notifications -> {
                     requestHighlightPreferenceKeyOnResume(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)
-                    replaceFragment(views.vectorSettingsPage, VectorSettingsNotificationPreferenceFragment::class.java, null, FRAGMENT_TAG)
+                    replaceFragment(views.vectorSettingsPage, VectorSettingsNotificationFragment::class.java, null, FRAGMENT_TAG)
                 }
                 is SettingsActivityPayload.DiscoverySettings -> {
                     replaceFragment(views.vectorSettingsPage, DiscoverySettingsFragment::class.java, payload, FRAGMENT_TAG)
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/PushRuleDefinitions.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/PushRuleDefinitions.kt
index 264da7c4a3..fff6ffe933 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/PushRuleDefinitions.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/PushRuleDefinitions.kt
@@ -38,7 +38,12 @@ fun getStandardAction(ruleId: String, index: NotificationIndex): StandardActions
                 NotificationIndex.SILENT -> StandardActions.Notify
                 NotificationIndex.NOISY -> StandardActions.Highlight
             }
-        RuleIds.RULE_ID_ONE_TO_ONE_ROOM ->
+        RuleIds.RULE_ID_ONE_TO_ONE_ROOM,
+        RuleIds.RULE_ID_POLL_START_ONE_TO_ONE,
+        RuleIds.RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE,
+        RuleIds.RULE_ID_POLL_END_ONE_TO_ONE,
+        RuleIds.RULE_ID_POLL_END_ONE_TO_ONE_UNSTABLE,
+        ->
             when (index) {
                 NotificationIndex.OFF -> StandardActions.DontNotify
                 NotificationIndex.SILENT -> StandardActions.Notify
@@ -50,7 +55,11 @@ fun getStandardAction(ruleId: String, index: NotificationIndex): StandardActions
                 NotificationIndex.SILENT -> StandardActions.Notify
                 NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
             }
-        RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS ->
+        RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS,
+        RuleIds.RULE_ID_POLL_START,
+        RuleIds.RULE_ID_POLL_START_UNSTABLE,
+        RuleIds.RULE_ID_POLL_END,
+        RuleIds.RULE_ID_POLL_END_UNSTABLE ->
             when (index) {
                 NotificationIndex.OFF -> StandardActions.DontNotify
                 NotificationIndex.SILENT -> StandardActions.Notify
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationFragment.kt
similarity index 95%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationFragment.kt
index 490a47ef61..dab7a9ed3a 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationFragment.kt
@@ -71,7 +71,7 @@ import javax.inject.Inject
 
 // Referenced in vector_settings_preferences_root.xml
 @AndroidEntryPoint
-class VectorSettingsNotificationPreferenceFragment :
+class VectorSettingsNotificationFragment :
         VectorSettingsBaseFragment(),
         BackgroundSyncModeChooserDialog.InteractionListener {
 
@@ -90,7 +90,7 @@ class VectorSettingsNotificationPreferenceFragment :
 
     private var interactionListener: VectorSettingsFragmentInteractionListener? = null
 
-    private val viewModel: VectorSettingsNotificationPreferenceViewModel by fragmentViewModel()
+    private val viewModel: VectorSettingsNotificationViewModel by fragmentViewModel()
 
     private val notificationStartForActivityResult = registerStartForActivityResult { _ ->
         // No op
@@ -116,10 +116,10 @@ class VectorSettingsNotificationPreferenceFragment :
     private fun observeViewEvents() {
         viewModel.observeViewEvents {
             when (it) {
-                VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled -> onNotificationsForDeviceEnabled()
-                VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled -> onNotificationsForDeviceDisabled()
-                is VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor -> askUserToSelectPushDistributor()
-                VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged -> onNotificationMethodChanged()
+                VectorSettingsNotificationViewEvent.NotificationsForDeviceEnabled -> onNotificationsForDeviceEnabled()
+                VectorSettingsNotificationViewEvent.NotificationsForDeviceDisabled -> onNotificationsForDeviceDisabled()
+                is VectorSettingsNotificationViewEvent.AskUserForPushDistributor -> askUserToSelectPushDistributor()
+                VectorSettingsNotificationViewEvent.NotificationMethodChanged -> onNotificationMethodChanged()
             }
         }
     }
@@ -143,9 +143,9 @@ class VectorSettingsNotificationPreferenceFragment :
         findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)
                 ?.setOnPreferenceChangeListener { _, isChecked ->
                     val action = if (isChecked as Boolean) {
-                        VectorSettingsNotificationPreferenceViewAction.EnableNotificationsForDevice(pushDistributor = "")
+                        VectorSettingsNotificationViewAction.EnableNotificationsForDevice(pushDistributor = "")
                     } else {
-                        VectorSettingsNotificationPreferenceViewAction.DisableNotificationsForDevice
+                        VectorSettingsNotificationViewAction.DisableNotificationsForDevice
                     }
                     viewModel.handle(action)
                     // preference will be updated on ViewEvent reception
@@ -231,9 +231,9 @@ class VectorSettingsNotificationPreferenceFragment :
     private fun askUserToSelectPushDistributor(withUnregister: Boolean = false) {
         unifiedPushHelper.showSelectDistributorDialog(requireContext()) { selection ->
             if (withUnregister) {
-                viewModel.handle(VectorSettingsNotificationPreferenceViewAction.RegisterPushDistributor(selection))
+                viewModel.handle(VectorSettingsNotificationViewAction.RegisterPushDistributor(selection))
             } else {
-                viewModel.handle(VectorSettingsNotificationPreferenceViewAction.EnableNotificationsForDevice(selection))
+                viewModel.handle(VectorSettingsNotificationViewAction.EnableNotificationsForDevice(selection))
             }
         }
     }
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewAction.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewAction.kt
similarity index 80%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewAction.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewAction.kt
index 949dc99993..4257f0a72b 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewAction.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewAction.kt
@@ -18,8 +18,8 @@ package im.vector.app.features.settings.notifications
 
 import im.vector.app.core.platform.VectorViewModelAction
 
-sealed interface VectorSettingsNotificationPreferenceViewAction : VectorViewModelAction {
-    data class EnableNotificationsForDevice(val pushDistributor: String) : VectorSettingsNotificationPreferenceViewAction
-    object DisableNotificationsForDevice : VectorSettingsNotificationPreferenceViewAction
-    data class RegisterPushDistributor(val pushDistributor: String) : VectorSettingsNotificationPreferenceViewAction
+sealed interface VectorSettingsNotificationViewAction : VectorViewModelAction {
+    data class EnableNotificationsForDevice(val pushDistributor: String) : VectorSettingsNotificationViewAction
+    object DisableNotificationsForDevice : VectorSettingsNotificationViewAction
+    data class RegisterPushDistributor(val pushDistributor: String) : VectorSettingsNotificationViewAction
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewEvent.kt
similarity index 84%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewEvent.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewEvent.kt
index b0ee107769..dd284a8bb1 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewEvent.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewEvent.kt
@@ -18,9 +18,9 @@ package im.vector.app.features.settings.notifications
 
 import im.vector.app.core.platform.VectorViewEvents
 
-sealed interface VectorSettingsNotificationPreferenceViewEvent : VectorViewEvents {
-    object NotificationsForDeviceEnabled : VectorSettingsNotificationPreferenceViewEvent
-    object NotificationsForDeviceDisabled : VectorSettingsNotificationPreferenceViewEvent
-    object AskUserForPushDistributor : VectorSettingsNotificationPreferenceViewEvent
-    object NotificationMethodChanged : VectorSettingsNotificationPreferenceViewEvent
+sealed interface VectorSettingsNotificationViewEvent : VectorViewEvents {
+    object NotificationsForDeviceEnabled : VectorSettingsNotificationViewEvent
+    object NotificationsForDeviceDisabled : VectorSettingsNotificationViewEvent
+    object AskUserForPushDistributor : VectorSettingsNotificationViewEvent
+    object NotificationMethodChanged : VectorSettingsNotificationViewEvent
 }
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewModel.kt
similarity index 74%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModel.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewModel.kt
index 9530be599e..c980288d76 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewModel.kt
@@ -31,9 +31,12 @@ import im.vector.app.core.pushers.PushersManager
 import im.vector.app.core.pushers.RegisterUnifiedPushUseCase
 import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
 import im.vector.app.features.settings.VectorPreferences
+import im.vector.app.features.settings.notifications.usecase.DisableNotificationsForCurrentSessionUseCase
+import im.vector.app.features.settings.notifications.usecase.EnableNotificationsForCurrentSessionUseCase
+import im.vector.app.features.settings.notifications.usecase.ToggleNotificationsForCurrentSessionUseCase
 import kotlinx.coroutines.launch
 
-class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
+class VectorSettingsNotificationViewModel @AssistedInject constructor(
         @Assisted initialState: VectorDummyViewState,
         private val pushersManager: PushersManager,
         private val vectorPreferences: VectorPreferences,
@@ -43,23 +46,23 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
         private val registerUnifiedPushUseCase: RegisterUnifiedPushUseCase,
         private val ensureFcmTokenIsRetrievedUseCase: EnsureFcmTokenIsRetrievedUseCase,
         private val toggleNotificationsForCurrentSessionUseCase: ToggleNotificationsForCurrentSessionUseCase,
-) : VectorViewModel<VectorDummyViewState, VectorSettingsNotificationPreferenceViewAction, VectorSettingsNotificationPreferenceViewEvent>(initialState) {
+) : VectorViewModel<VectorDummyViewState, VectorSettingsNotificationViewAction, VectorSettingsNotificationViewEvent>(initialState) {
 
     @AssistedFactory
-    interface Factory : MavericksAssistedViewModelFactory<VectorSettingsNotificationPreferenceViewModel, VectorDummyViewState> {
-        override fun create(initialState: VectorDummyViewState): VectorSettingsNotificationPreferenceViewModel
+    interface Factory : MavericksAssistedViewModelFactory<VectorSettingsNotificationViewModel, VectorDummyViewState> {
+        override fun create(initialState: VectorDummyViewState): VectorSettingsNotificationViewModel
     }
 
-    companion object : MavericksViewModelFactory<VectorSettingsNotificationPreferenceViewModel, VectorDummyViewState> by hiltMavericksViewModelFactory()
+    companion object : MavericksViewModelFactory<VectorSettingsNotificationViewModel, VectorDummyViewState> by hiltMavericksViewModelFactory()
 
     @VisibleForTesting
     val notificationsPreferenceListener: SharedPreferences.OnSharedPreferenceChangeListener =
             SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
                 if (key == VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY) {
                     if (vectorPreferences.areNotificationEnabledForDevice()) {
-                        _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled)
+                        _viewEvents.post(VectorSettingsNotificationViewEvent.NotificationsForDeviceEnabled)
                     } else {
-                        _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled)
+                        _viewEvents.post(VectorSettingsNotificationViewEvent.NotificationsForDeviceDisabled)
                     }
                 }
             }
@@ -77,18 +80,18 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
         super.onCleared()
     }
 
-    override fun handle(action: VectorSettingsNotificationPreferenceViewAction) {
+    override fun handle(action: VectorSettingsNotificationViewAction) {
         when (action) {
-            VectorSettingsNotificationPreferenceViewAction.DisableNotificationsForDevice -> handleDisableNotificationsForDevice()
-            is VectorSettingsNotificationPreferenceViewAction.EnableNotificationsForDevice -> handleEnableNotificationsForDevice(action.pushDistributor)
-            is VectorSettingsNotificationPreferenceViewAction.RegisterPushDistributor -> handleRegisterPushDistributor(action.pushDistributor)
+            VectorSettingsNotificationViewAction.DisableNotificationsForDevice -> handleDisableNotificationsForDevice()
+            is VectorSettingsNotificationViewAction.EnableNotificationsForDevice -> handleEnableNotificationsForDevice(action.pushDistributor)
+            is VectorSettingsNotificationViewAction.RegisterPushDistributor -> handleRegisterPushDistributor(action.pushDistributor)
         }
     }
 
     private fun handleDisableNotificationsForDevice() {
         viewModelScope.launch {
             disableNotificationsForCurrentSessionUseCase.execute()
-            _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled)
+            _viewEvents.post(VectorSettingsNotificationViewEvent.NotificationsForDeviceDisabled)
         }
     }
 
@@ -96,10 +99,10 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
         viewModelScope.launch {
             when (enableNotificationsForCurrentSessionUseCase.execute(distributor)) {
                 is EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.NeedToAskUserForDistributor -> {
-                    _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor)
+                    _viewEvents.post(VectorSettingsNotificationViewEvent.AskUserForPushDistributor)
                 }
                 EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.Success -> {
-                    _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled)
+                    _viewEvents.post(VectorSettingsNotificationViewEvent.NotificationsForDeviceEnabled)
                 }
             }
         }
@@ -110,13 +113,13 @@ class VectorSettingsNotificationPreferenceViewModel @AssistedInject constructor(
             unregisterUnifiedPushUseCase.execute(pushersManager)
             when (registerUnifiedPushUseCase.execute(distributor)) {
                 RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.NeedToAskUserForDistributor -> {
-                    _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor)
+                    _viewEvents.post(VectorSettingsNotificationViewEvent.AskUserForPushDistributor)
                 }
                 RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.Success -> {
                     val areNotificationsEnabled = vectorPreferences.areNotificationEnabledForDevice()
                     ensureFcmTokenIsRetrievedUseCase.execute(pushersManager, registerPusher = areNotificationsEnabled)
                     toggleNotificationsForCurrentSessionUseCase.execute(enabled = areNotificationsEnabled)
-                    _viewEvents.post(VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged)
+                    _viewEvents.post(VectorSettingsNotificationViewEvent.NotificationMethodChanged)
                 }
             }
         }
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationFragment.kt
new file mode 100644
index 0000000000..0f991867fe
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationFragment.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.settings.notifications
+
+import android.os.Bundle
+import android.view.View
+import androidx.preference.Preference
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.app.core.preference.VectorCheckboxPreference
+import im.vector.app.features.settings.VectorSettingsBaseFragment
+
+abstract class VectorSettingsPushRuleNotificationFragment :
+        VectorSettingsBaseFragment() {
+
+    private val viewModel: VectorSettingsPushRuleNotificationViewModel by fragmentViewModel()
+
+    abstract val prefKeyToPushRuleId: Map<String, String>
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        observeViewEvents()
+        viewModel.onEach(VectorSettingsPushRuleNotificationViewState::isLoading) { isLoading ->
+            if (isLoading) {
+                displayLoadingView()
+            } else {
+                hideLoadingView()
+            }
+        }
+    }
+
+    private fun observeViewEvents() {
+        viewModel.observeViewEvents {
+            when (it) {
+                is VectorSettingsPushRuleNotificationViewEvent.Failure -> refreshDisplay()
+                is VectorSettingsPushRuleNotificationViewEvent.PushRuleUpdated -> updatePreference(it.ruleId, it.checked)
+            }
+        }
+    }
+
+    override fun bindPref() {
+        for (preferenceKey in prefKeyToPushRuleId.keys) {
+            val preference = findPreference<VectorCheckboxPreference>(preferenceKey)!!
+            preference.isIconSpaceReserved = false
+            val ruleAndKind = prefKeyToPushRuleId[preferenceKey]?.let { viewModel.getPushRuleAndKind(it) }
+            if (ruleAndKind == null) {
+                // The rule is not defined, hide the preference
+                preference.isVisible = false
+            } else {
+                preference.isVisible = true
+                updatePreference(ruleAndKind.pushRule.ruleId, viewModel.isPushRuleChecked(ruleAndKind.pushRule.ruleId))
+                preference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
+                    viewModel.handle(VectorSettingsPushRuleNotificationViewAction.UpdatePushRule(ruleAndKind, newValue as Boolean))
+                    false
+                }
+            }
+        }
+    }
+
+    override fun invalidate() = withState(viewModel) { state ->
+        if (state.isLoading) {
+            displayLoadingView()
+        } else {
+            hideLoadingView()
+        }
+    }
+
+    protected fun refreshDisplay() {
+        listView?.adapter?.notifyDataSetChanged()
+    }
+
+    private fun updatePreference(ruleId: String, checked: Boolean) {
+        val preferenceKey = prefKeyToPushRuleId.entries.find { it.value == ruleId }?.key ?: return
+        val preference = findPreference<VectorCheckboxPreference>(preferenceKey) ?: return
+        preference.isChecked = checked
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceFragment.kt
deleted file mode 100644
index 7f856298ea..0000000000
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationPreferenceFragment.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2021 New Vector Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package im.vector.app.features.settings.notifications
-
-import androidx.lifecycle.lifecycleScope
-import androidx.preference.Preference
-import im.vector.app.core.preference.VectorCheckboxPreference
-import im.vector.app.features.settings.VectorSettingsBaseFragment
-import kotlinx.coroutines.launch
-import org.matrix.android.sdk.api.session.pushrules.RuleKind
-import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind
-
-abstract class VectorSettingsPushRuleNotificationPreferenceFragment :
-        VectorSettingsBaseFragment() {
-
-    abstract val prefKeyToPushRuleId: Map<String, String>
-
-    override fun bindPref() {
-        for (preferenceKey in prefKeyToPushRuleId.keys) {
-            val preference = findPreference<VectorCheckboxPreference>(preferenceKey)!!
-            preference.isIconSpaceReserved = false
-            val ruleAndKind: PushRuleAndKind? = session.pushRuleService().getPushRules().findDefaultRule(prefKeyToPushRuleId[preferenceKey])
-            if (ruleAndKind == null) {
-                // The rule is not defined, hide the preference
-                preference.isVisible = false
-            } else {
-                preference.isVisible = true
-                val initialIndex = ruleAndKind.pushRule.notificationIndex
-                preference.isChecked = initialIndex != NotificationIndex.OFF
-                preference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
-                    updatePushRule(ruleAndKind.pushRule.ruleId, ruleAndKind.kind, newValue as Boolean, preference)
-                    false
-                }
-            }
-        }
-    }
-
-    fun updatePushRule(ruleId: String, kind: RuleKind, checked: Boolean, preference: VectorCheckboxPreference) {
-        val newIndex = if (checked) NotificationIndex.NOISY else NotificationIndex.OFF
-        val standardAction = getStandardAction(ruleId, newIndex) ?: return
-        val enabled = standardAction != StandardActions.Disabled
-        val newActions = standardAction.actions
-        displayLoadingView()
-
-        lifecycleScope.launch {
-            val result = runCatching {
-                session.pushRuleService().updatePushRuleActions(
-                        kind,
-                        ruleId,
-                        enabled,
-                        newActions
-                )
-            }
-            hideLoadingView()
-            if (!isAdded) {
-                return@launch
-            }
-            result.onSuccess {
-                preference.isChecked = checked
-            }
-            result.onFailure { failure ->
-                // Restore the previous value
-                refreshDisplay()
-                displayErrorDialog(failure)
-            }
-        }
-    }
-
-    fun refreshDisplay() {
-        listView?.adapter?.notifyDataSetChanged()
-    }
-}
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewAction.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewAction.kt
new file mode 100644
index 0000000000..61bf7c5b15
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewAction.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.settings.notifications
+
+import im.vector.app.core.platform.VectorViewModelAction
+import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind
+
+sealed interface VectorSettingsPushRuleNotificationViewAction : VectorViewModelAction {
+    data class UpdatePushRule(val pushRuleAndKind: PushRuleAndKind, val checked: Boolean) : VectorSettingsPushRuleNotificationViewAction
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewEvent.kt
new file mode 100644
index 0000000000..adfc17f827
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewEvent.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.settings.notifications
+
+import im.vector.app.core.platform.VectorViewEvents
+
+sealed interface VectorSettingsPushRuleNotificationViewEvent : VectorViewEvents {
+    /**
+     * A global push rule checked state has changed.
+     *
+     * @property ruleId the global rule id which has been updated.
+     * @property checked whether the global rule is checked.
+     * @property failure whether there has been a failure when updating the global rule (ie. a sub rule has not been updated).
+     */
+    data class PushRuleUpdated(val ruleId: String, val checked: Boolean, val failure: Throwable? = null) : VectorSettingsPushRuleNotificationViewEvent
+
+    /**
+     * A failure has occurred.
+     *
+     * @property throwable the related exception, if any.
+     */
+    data class Failure(val throwable: Throwable?) : VectorSettingsPushRuleNotificationViewEvent
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewModel.kt
new file mode 100644
index 0000000000..39969ec13e
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewModel.kt
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.settings.notifications
+
+import com.airbnb.mvrx.MavericksViewModelFactory
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import im.vector.app.core.di.ActiveSessionHolder
+import im.vector.app.core.di.MavericksAssistedViewModelFactory
+import im.vector.app.core.di.hiltMavericksViewModelFactory
+import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.features.settings.notifications.VectorSettingsPushRuleNotificationViewEvent.Failure
+import im.vector.app.features.settings.notifications.VectorSettingsPushRuleNotificationViewEvent.PushRuleUpdated
+import kotlinx.coroutines.launch
+import org.matrix.android.sdk.api.failure.Failure.ServerError
+import org.matrix.android.sdk.api.failure.MatrixError
+import org.matrix.android.sdk.api.session.pushrules.Action
+import org.matrix.android.sdk.api.session.pushrules.RuleIds
+import org.matrix.android.sdk.api.session.pushrules.RuleKind
+import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind
+
+private typealias ViewModel = VectorSettingsPushRuleNotificationViewModel
+private typealias ViewState = VectorSettingsPushRuleNotificationViewState
+
+class VectorSettingsPushRuleNotificationViewModel @AssistedInject constructor(
+        @Assisted initialState: ViewState,
+        private val activeSessionHolder: ActiveSessionHolder,
+) : VectorViewModel<VectorSettingsPushRuleNotificationViewState,
+        VectorSettingsPushRuleNotificationViewAction,
+        VectorSettingsPushRuleNotificationViewEvent>(initialState) {
+
+    @AssistedFactory
+    interface Factory : MavericksAssistedViewModelFactory<ViewModel, ViewState> {
+        override fun create(initialState: ViewState): ViewModel
+    }
+
+    companion object : MavericksViewModelFactory<ViewModel, ViewState> by hiltMavericksViewModelFactory()
+
+    override fun handle(action: VectorSettingsPushRuleNotificationViewAction) {
+        when (action) {
+            is VectorSettingsPushRuleNotificationViewAction.UpdatePushRule -> handleUpdatePushRule(action.pushRuleAndKind, action.checked)
+        }
+    }
+
+    fun getPushRuleAndKind(ruleId: String): PushRuleAndKind? {
+        return activeSessionHolder.getSafeActiveSession()?.pushRuleService()?.getPushRules()?.findDefaultRule(ruleId)
+    }
+
+    fun isPushRuleChecked(ruleId: String): Boolean {
+        val rulesGroup = listOf(ruleId) + RuleIds.getSyncedRules(ruleId)
+        return rulesGroup.mapNotNull { getPushRuleAndKind(it) }.any { it.pushRule.notificationIndex != NotificationIndex.OFF }
+    }
+
+    private fun handleUpdatePushRule(pushRuleAndKind: PushRuleAndKind, checked: Boolean) {
+        val ruleId = pushRuleAndKind.pushRule.ruleId
+        val kind = pushRuleAndKind.kind
+        val newIndex = if (checked) NotificationIndex.NOISY else NotificationIndex.OFF
+        val standardAction = getStandardAction(ruleId, newIndex) ?: return
+        val enabled = standardAction != StandardActions.Disabled
+        val newActions = standardAction.actions
+        setState { copy(isLoading = true) }
+
+        viewModelScope.launch {
+            val rulesToUpdate = listOf(ruleId) + RuleIds.getSyncedRules(ruleId)
+            val results = rulesToUpdate.map { ruleId ->
+                runCatching {
+                    updatePushRule(kind, ruleId, enabled, newActions)
+                }
+            }
+            setState { copy(isLoading = false) }
+            val failure = results.firstNotNullOfOrNull { result ->
+                // If the failure is a rule not found error, do not consider it
+                result.exceptionOrNull()?.takeUnless { it is ServerError && it.error.code == MatrixError.M_NOT_FOUND }
+            }
+            val newChecked = if (checked) {
+                // If any rule is checked, the global rule is checked
+                results.any { it.isSuccess }
+            } else {
+                // If any rule has not been unchecked, the global rule remains checked
+                failure != null
+            }
+            if (results.any { it.isSuccess }) {
+                _viewEvents.post(PushRuleUpdated(ruleId, newChecked, failure))
+            } else {
+                _viewEvents.post(Failure(failure))
+            }
+        }
+    }
+
+    private suspend fun updatePushRule(kind: RuleKind, ruleId: String, enable: Boolean, newActions: List<Action>?) {
+        activeSessionHolder.getSafeActiveSession()?.pushRuleService()?.updatePushRuleActions(
+                kind = kind,
+                ruleId = ruleId,
+                enable = enable,
+                actions = newActions
+        )
+    }
+}
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewState.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewState.kt
new file mode 100644
index 0000000000..477727aee6
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewState.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.settings.notifications
+
+import com.airbnb.mvrx.MavericksState
+
+data class VectorSettingsPushRuleNotificationViewState(
+        val isLoading: Boolean = false,
+) : MavericksState
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsAdvancedNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/advanced/VectorSettingsAdvancedNotificationPreferenceFragment.kt
similarity index 89%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsAdvancedNotificationPreferenceFragment.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/advanced/VectorSettingsAdvancedNotificationPreferenceFragment.kt
index 183d997ffb..44d7330d39 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsAdvancedNotificationPreferenceFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/advanced/VectorSettingsAdvancedNotificationPreferenceFragment.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2023 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.advanced
 
 import androidx.lifecycle.lifecycleScope
 import androidx.preference.Preference
@@ -23,10 +23,15 @@ import im.vector.app.core.preference.PushRulePreference
 import im.vector.app.core.preference.VectorPreference
 import im.vector.app.core.utils.toast
 import im.vector.app.features.settings.VectorSettingsBaseFragment
+import im.vector.app.features.settings.notifications.NotificationIndex
+import im.vector.app.features.settings.notifications.StandardActions
+import im.vector.app.features.settings.notifications.getStandardAction
+import im.vector.app.features.settings.notifications.notificationIndex
 import kotlinx.coroutines.launch
 import org.matrix.android.sdk.api.session.pushrules.RuleIds
 import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind
 
+// TODO This fragment seems not used anymore, we can probably delete it
 @AndroidEntryPoint
 class VectorSettingsAdvancedNotificationPreferenceFragment :
         VectorSettingsBaseFragment() {
@@ -39,7 +44,7 @@ class VectorSettingsAdvancedNotificationPreferenceFragment :
         for (preferenceKey in prefKeyToPushRuleId.keys) {
             val preference = findPreference<VectorPreference>(preferenceKey)
             if (preference is PushRulePreference) {
-                val ruleAndKind: PushRuleAndKind? = session.pushRuleService().getPushRules().findDefaultRule(prefKeyToPushRuleId[preferenceKey])
+                val ruleAndKind: PushRuleAndKind? = prefKeyToPushRuleId[preferenceKey]?.let { session.pushRuleService().getPushRules().findDefaultRule(it) }
 
                 if (ruleAndKind == null) {
                     // The rule is not defined, hide the preference
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsDefaultNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/defaults/VectorSettingsDefaultNotificationFragment.kt
similarity index 85%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsDefaultNotificationPreferenceFragment.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/defaults/VectorSettingsDefaultNotificationFragment.kt
index 33ed7730eb..009213ceff 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsDefaultNotificationPreferenceFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/defaults/VectorSettingsDefaultNotificationFragment.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2023 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.defaults
 
 import android.os.Bundle
 import im.vector.app.R
 import im.vector.app.core.preference.VectorPreferenceCategory
 import im.vector.app.features.analytics.plan.MobileScreen
+import im.vector.app.features.settings.notifications.VectorSettingsPushRuleNotificationFragment
 import org.matrix.android.sdk.api.session.pushrules.RuleIds
 
-class VectorSettingsDefaultNotificationPreferenceFragment :
-        VectorSettingsPushRuleNotificationPreferenceFragment() {
+class VectorSettingsDefaultNotificationFragment :
+        VectorSettingsPushRuleNotificationFragment() {
 
     override var titleRes: Int = R.string.settings_notification_default
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsKeywordAndMentionsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/keywordandmentions/VectorSettingsKeywordAndMentionsNotificationFragment.kt
similarity index 93%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsKeywordAndMentionsNotificationPreferenceFragment.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/keywordandmentions/VectorSettingsKeywordAndMentionsNotificationFragment.kt
index d0a1bff50c..c408b8ea91 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsKeywordAndMentionsNotificationPreferenceFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/keywordandmentions/VectorSettingsKeywordAndMentionsNotificationFragment.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2023 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.keywordandmentions
 
 import android.os.Bundle
 import android.view.View
@@ -26,6 +26,10 @@ import im.vector.app.core.preference.VectorCheckboxPreference
 import im.vector.app.core.preference.VectorPreference
 import im.vector.app.core.preference.VectorPreferenceCategory
 import im.vector.app.features.analytics.plan.MobileScreen
+import im.vector.app.features.settings.notifications.NotificationIndex
+import im.vector.app.features.settings.notifications.StandardActions
+import im.vector.app.features.settings.notifications.VectorSettingsPushRuleNotificationFragment
+import im.vector.app.features.settings.notifications.getStandardAction
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
@@ -34,8 +38,8 @@ import org.matrix.android.sdk.api.session.pushrules.RuleKind
 import org.matrix.android.sdk.api.session.pushrules.rest.PushRule
 import org.matrix.android.sdk.api.session.pushrules.toJson
 
-class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment :
-        VectorSettingsPushRuleNotificationPreferenceFragment() {
+class VectorSettingsKeywordAndMentionsNotificationFragment :
+        VectorSettingsPushRuleNotificationFragment() {
 
     override var titleRes: Int = R.string.settings_notification_mentions_and_keywords
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsOtherNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/other/VectorSettingsOtherNotificationFragment.kt
similarity index 83%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsOtherNotificationPreferenceFragment.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/other/VectorSettingsOtherNotificationFragment.kt
index 3638fb8526..5f8ad08a80 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsOtherNotificationPreferenceFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/other/VectorSettingsOtherNotificationFragment.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright (c) 2023 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.other
 
 import im.vector.app.R
 import im.vector.app.core.preference.VectorPreferenceCategory
+import im.vector.app.features.settings.notifications.VectorSettingsPushRuleNotificationFragment
 import org.matrix.android.sdk.api.session.pushrules.RuleIds
 
-class VectorSettingsOtherNotificationPreferenceFragment :
-        VectorSettingsPushRuleNotificationPreferenceFragment() {
+class VectorSettingsOtherNotificationFragment :
+        VectorSettingsPushRuleNotificationFragment() {
 
     override var titleRes: Int = R.string.settings_notification_other
 
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationsTroubleshootFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/troubleshoot/VectorSettingsNotificationsTroubleshootFragment.kt
similarity index 99%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationsTroubleshootFragment.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/troubleshoot/VectorSettingsNotificationsTroubleshootFragment.kt
index c5d15e54e5..b814c981c9 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationsTroubleshootFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/troubleshoot/VectorSettingsNotificationsTroubleshootFragment.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.troubleshoot
 
 import android.app.Activity
 import android.content.BroadcastReceiver
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/usecase/DisableNotificationsForCurrentSessionUseCase.kt
similarity index 92%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/usecase/DisableNotificationsForCurrentSessionUseCase.kt
index 0c50a296f3..9ce0307820 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/usecase/DisableNotificationsForCurrentSessionUseCase.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 New Vector Ltd
+ * Copyright (c) 2023 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.usecase
 
 import im.vector.app.core.pushers.PushersManager
 import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/usecase/EnableNotificationsForCurrentSessionUseCase.kt
similarity index 95%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/usecase/EnableNotificationsForCurrentSessionUseCase.kt
index daf3890e33..2bb350b6ac 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/usecase/EnableNotificationsForCurrentSessionUseCase.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 New Vector Ltd
+ * Copyright (c) 2023 New Vector Ltd
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.usecase
 
 import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase
 import im.vector.app.core.pushers.PushersManager
diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/usecase/ToggleNotificationsForCurrentSessionUseCase.kt
similarity index 97%
rename from vector/src/main/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCase.kt
rename to vector/src/main/java/im/vector/app/features/settings/notifications/usecase/ToggleNotificationsForCurrentSessionUseCase.kt
index 3dc73f0a31..c717ab7657 100644
--- a/vector/src/main/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCase.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/notifications/usecase/ToggleNotificationsForCurrentSessionUseCase.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package im.vector.app.features.settings.notifications
+package im.vector.app.features.settings.notifications.usecase
 
 import im.vector.app.core.di.ActiveSessionHolder
 import im.vector.app.core.pushers.UnifiedPushHelper
diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml
index f4d7ff8cd5..87f344fc54 100644
--- a/vector/src/main/res/xml/vector_settings_notifications.xml
+++ b/vector/src/main/res/xml/vector_settings_notifications.xml
@@ -25,21 +25,21 @@
             android:key="SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY"
             android:persistent="false"
             android:title="@string/settings_notification_default"
-            app:fragment="im.vector.app.features.settings.notifications.VectorSettingsDefaultNotificationPreferenceFragment" />
+            app:fragment="im.vector.app.features.settings.notifications.defaults.VectorSettingsDefaultNotificationFragment" />
 
         <im.vector.app.core.preference.VectorPreference
             android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
             android:key="SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY"
             android:persistent="false"
             android:title="@string/settings_notification_mentions_and_keywords"
-            app:fragment="im.vector.app.features.settings.notifications.VectorSettingsKeywordAndMentionsNotificationPreferenceFragment" />
+            app:fragment="im.vector.app.features.settings.notifications.keywordandmentions.VectorSettingsKeywordAndMentionsNotificationFragment" />
 
         <im.vector.app.core.preference.VectorPreference
             android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
             android:key="SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY"
             android:persistent="false"
             android:title="@string/settings_notification_other"
-            app:fragment="im.vector.app.features.settings.notifications.VectorSettingsOtherNotificationPreferenceFragment" />
+            app:fragment="im.vector.app.features.settings.notifications.other.VectorSettingsOtherNotificationFragment" />
 
     </im.vector.app.core.preference.VectorPreferenceCategory>
 
@@ -119,7 +119,7 @@
         <im.vector.app.core.preference.VectorPreference
             android:key="SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY"
             android:title="@string/settings_notification_troubleshoot"
-            app:fragment="im.vector.app.features.settings.notifications.VectorSettingsNotificationsTroubleshootFragment" />
+            app:fragment="im.vector.app.features.settings.notifications.troubleshoot.VectorSettingsNotificationsTroubleshootFragment" />
 
     </im.vector.app.core.preference.VectorPreferenceCategory>
 
diff --git a/vector/src/main/res/xml/vector_settings_root.xml b/vector/src/main/res/xml/vector_settings_root.xml
index ffa8688cbd..59548d10cb 100644
--- a/vector/src/main/res/xml/vector_settings_root.xml
+++ b/vector/src/main/res/xml/vector_settings_root.xml
@@ -11,7 +11,7 @@
     <im.vector.app.core.preference.VectorPreference
         android:icon="@drawable/ic_settings_root_notification"
         android:title="@string/settings_notifications"
-        app:fragment="im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment"
+        app:fragment="im.vector.app.features.settings.notifications.VectorSettingsNotificationFragment"
         app:isPreferenceVisible="@bool/settings_root_notification_visible" />
 
     <im.vector.app.core.preference.VectorPreference
diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt
index 669b20fc1a..ceb6fd9217 100644
--- a/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt
+++ b/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt
@@ -17,6 +17,8 @@
 package im.vector.app.features.settings.notifications
 
 import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
+import im.vector.app.features.settings.notifications.usecase.DisableNotificationsForCurrentSessionUseCase
+import im.vector.app.features.settings.notifications.usecase.ToggleNotificationsForCurrentSessionUseCase
 import im.vector.app.test.fakes.FakePushersManager
 import io.mockk.coJustRun
 import io.mockk.coVerify
diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt
index d58ba7645c..fa5d0a8bd1 100644
--- a/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt
+++ b/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt
@@ -18,6 +18,8 @@ package im.vector.app.features.settings.notifications
 
 import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase
 import im.vector.app.core.pushers.RegisterUnifiedPushUseCase
+import im.vector.app.features.settings.notifications.usecase.EnableNotificationsForCurrentSessionUseCase
+import im.vector.app.features.settings.notifications.usecase.ToggleNotificationsForCurrentSessionUseCase
 import im.vector.app.test.fakes.FakePushersManager
 import io.mockk.coJustRun
 import io.mockk.coVerify
diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCaseTest.kt
index f49aafab8a..83a4265ace 100644
--- a/vector/src/test/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCaseTest.kt
+++ b/vector/src/test/java/im/vector/app/features/settings/notifications/ToggleNotificationsForCurrentSessionUseCaseTest.kt
@@ -19,6 +19,7 @@ package im.vector.app.features.settings.notifications
 import im.vector.app.features.settings.devices.v2.notification.CheckIfCanToggleNotificationsViaPusherUseCase
 import im.vector.app.features.settings.devices.v2.notification.DeleteNotificationSettingsAccountDataUseCase
 import im.vector.app.features.settings.devices.v2.notification.SetNotificationSettingsAccountDataUseCase
+import im.vector.app.features.settings.notifications.usecase.ToggleNotificationsForCurrentSessionUseCase
 import im.vector.app.test.fakes.FakeActiveSessionHolder
 import im.vector.app.test.fakes.FakeUnifiedPushHelper
 import im.vector.app.test.fixtures.PusherFixture
diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewModelTest.kt
similarity index 85%
rename from vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModelTest.kt
rename to vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewModelTest.kt
index ae36ee7600..ad7adc6b69 100644
--- a/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceViewModelTest.kt
+++ b/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationViewModelTest.kt
@@ -22,6 +22,9 @@ import im.vector.app.core.pushers.EnsureFcmTokenIsRetrievedUseCase
 import im.vector.app.core.pushers.RegisterUnifiedPushUseCase
 import im.vector.app.core.pushers.UnregisterUnifiedPushUseCase
 import im.vector.app.features.settings.VectorPreferences.Companion.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY
+import im.vector.app.features.settings.notifications.usecase.DisableNotificationsForCurrentSessionUseCase
+import im.vector.app.features.settings.notifications.usecase.EnableNotificationsForCurrentSessionUseCase
+import im.vector.app.features.settings.notifications.usecase.ToggleNotificationsForCurrentSessionUseCase
 import im.vector.app.test.fakes.FakePushersManager
 import im.vector.app.test.fakes.FakeVectorPreferences
 import im.vector.app.test.test
@@ -35,7 +38,7 @@ import io.mockk.mockk
 import org.junit.Rule
 import org.junit.Test
 
-class VectorSettingsNotificationPreferenceViewModelTest {
+class VectorSettingsNotificationViewModelTest {
 
     @get:Rule
     val mavericksTestRule = MavericksTestRule(testDispatcher = testDispatcher)
@@ -49,7 +52,7 @@ class VectorSettingsNotificationPreferenceViewModelTest {
     private val fakeEnsureFcmTokenIsRetrievedUseCase = mockk<EnsureFcmTokenIsRetrievedUseCase>()
     private val fakeToggleNotificationsForCurrentSessionUseCase = mockk<ToggleNotificationsForCurrentSessionUseCase>()
 
-    private fun createViewModel() = VectorSettingsNotificationPreferenceViewModel(
+    private fun createViewModel() = VectorSettingsNotificationViewModel(
             initialState = VectorDummyViewState(),
             pushersManager = fakePushersManager.instance,
             vectorPreferences = fakeVectorPreferences.instance,
@@ -65,7 +68,7 @@ class VectorSettingsNotificationPreferenceViewModelTest {
     fun `given view model init when notifications are enabled in preferences then view event is posted`() {
         // Given
         fakeVectorPreferences.givenAreNotificationsEnabledForDevice(true)
-        val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled
+        val expectedEvent = VectorSettingsNotificationViewEvent.NotificationsForDeviceEnabled
         val viewModel = createViewModel()
 
         // When
@@ -82,7 +85,7 @@ class VectorSettingsNotificationPreferenceViewModelTest {
     fun `given view model init when notifications are disabled in preferences then view event is posted`() {
         // Given
         fakeVectorPreferences.givenAreNotificationsEnabledForDevice(false)
-        val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled
+        val expectedEvent = VectorSettingsNotificationViewEvent.NotificationsForDeviceDisabled
         val viewModel = createViewModel()
 
         // When
@@ -99,9 +102,9 @@ class VectorSettingsNotificationPreferenceViewModelTest {
     fun `given DisableNotificationsForDevice action when handling action then disable use case is called`() {
         // Given
         val viewModel = createViewModel()
-        val action = VectorSettingsNotificationPreferenceViewAction.DisableNotificationsForDevice
+        val action = VectorSettingsNotificationViewAction.DisableNotificationsForDevice
         coJustRun { fakeDisableNotificationsForCurrentSessionUseCase.execute() }
-        val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceDisabled
+        val expectedEvent = VectorSettingsNotificationViewEvent.NotificationsForDeviceDisabled
 
         // When
         val viewModelTest = viewModel.test()
@@ -121,10 +124,10 @@ class VectorSettingsNotificationPreferenceViewModelTest {
         // Given
         val viewModel = createViewModel()
         val aDistributor = "aDistributor"
-        val action = VectorSettingsNotificationPreferenceViewAction.EnableNotificationsForDevice(aDistributor)
+        val action = VectorSettingsNotificationViewAction.EnableNotificationsForDevice(aDistributor)
         coEvery { fakeEnableNotificationsForCurrentSessionUseCase.execute(any()) } returns
                 EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.Success
-        val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationsForDeviceEnabled
+        val expectedEvent = VectorSettingsNotificationViewEvent.NotificationsForDeviceEnabled
 
         // When
         val viewModelTest = viewModel.test()
@@ -144,10 +147,10 @@ class VectorSettingsNotificationPreferenceViewModelTest {
         // Given
         val viewModel = createViewModel()
         val aDistributor = "aDistributor"
-        val action = VectorSettingsNotificationPreferenceViewAction.EnableNotificationsForDevice(aDistributor)
+        val action = VectorSettingsNotificationViewAction.EnableNotificationsForDevice(aDistributor)
         coEvery { fakeEnableNotificationsForCurrentSessionUseCase.execute(any()) } returns
                 EnableNotificationsForCurrentSessionUseCase.EnableNotificationsResult.NeedToAskUserForDistributor
-        val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor
+        val expectedEvent = VectorSettingsNotificationViewEvent.AskUserForPushDistributor
 
         // When
         val viewModelTest = viewModel.test()
@@ -167,14 +170,14 @@ class VectorSettingsNotificationPreferenceViewModelTest {
         // Given
         val viewModel = createViewModel()
         val aDistributor = "aDistributor"
-        val action = VectorSettingsNotificationPreferenceViewAction.RegisterPushDistributor(aDistributor)
+        val action = VectorSettingsNotificationViewAction.RegisterPushDistributor(aDistributor)
         coEvery { fakeRegisterUnifiedPushUseCase.execute(any()) } returns RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.Success
         coJustRun { fakeUnregisterUnifiedPushUseCase.execute(any()) }
         val areNotificationsEnabled = true
         fakeVectorPreferences.givenAreNotificationsEnabledForDevice(areNotificationsEnabled)
         coJustRun { fakeToggleNotificationsForCurrentSessionUseCase.execute(any()) }
         justRun { fakeEnsureFcmTokenIsRetrievedUseCase.execute(any(), any()) }
-        val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.NotificationMethodChanged
+        val expectedEvent = VectorSettingsNotificationViewEvent.NotificationMethodChanged
 
         // When
         val viewModelTest = viewModel.test()
@@ -197,10 +200,10 @@ class VectorSettingsNotificationPreferenceViewModelTest {
         // Given
         val viewModel = createViewModel()
         val aDistributor = "aDistributor"
-        val action = VectorSettingsNotificationPreferenceViewAction.RegisterPushDistributor(aDistributor)
+        val action = VectorSettingsNotificationViewAction.RegisterPushDistributor(aDistributor)
         coEvery { fakeRegisterUnifiedPushUseCase.execute(any()) } returns RegisterUnifiedPushUseCase.RegisterUnifiedPushResult.NeedToAskUserForDistributor
         coJustRun { fakeUnregisterUnifiedPushUseCase.execute(any()) }
-        val expectedEvent = VectorSettingsNotificationPreferenceViewEvent.AskUserForPushDistributor
+        val expectedEvent = VectorSettingsNotificationViewEvent.AskUserForPushDistributor
 
         // When
         val viewModelTest = viewModel.test()
diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewModelTest.kt
new file mode 100644
index 0000000000..04a22bc21f
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/features/settings/notifications/VectorSettingsPushRuleNotificationViewModelTest.kt
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2023 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.features.settings.notifications
+
+import com.airbnb.mvrx.test.MavericksTestRule
+import im.vector.app.test.fakes.FakeActiveSessionHolder
+import im.vector.app.test.test
+import im.vector.app.test.testDispatcher
+import io.mockk.coVerifyOrder
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.mockkStatic
+import io.mockk.unmockkAll
+import kotlinx.coroutines.test.runTest
+import org.amshove.kluent.shouldBe
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.matrix.android.sdk.api.session.pushrules.RuleIds
+import org.matrix.android.sdk.api.session.pushrules.rest.PushRuleAndKind
+
+internal class VectorSettingsPushRuleNotificationViewModelTest {
+
+    @get:Rule
+    val mavericksTestRule = MavericksTestRule(testDispatcher = testDispatcher)
+
+    private val fakeActiveSessionHolder = FakeActiveSessionHolder()
+    private val fakePushRuleService = fakeActiveSessionHolder.fakeSession.fakePushRuleService
+
+    private val initialState = VectorSettingsPushRuleNotificationViewState()
+    private fun createViewModel() = VectorSettingsPushRuleNotificationViewModel(
+            initialState = initialState,
+            activeSessionHolder = fakeActiveSessionHolder.instance,
+    )
+
+    @Before
+    fun setup() {
+        mockkStatic("im.vector.app.features.settings.notifications.NotificationIndexKt")
+    }
+
+    @After
+    fun tearDown() {
+        unmockkAll()
+    }
+
+    @Test
+    fun `given a ruleId, when the rule is checked or unchecked with no error, then the expected view event is posted`() = runTest {
+        // Given
+        val viewModel = createViewModel()
+
+        val firstRuleId = RuleIds.RULE_ID_ONE_TO_ONE_ROOM
+        val secondRuleId = RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS
+        fakePushRuleService.givenUpdatePushRuleActionsSucceed()
+
+        // When
+        val viewModelTest = viewModel.test()
+        viewModel.handle(VectorSettingsPushRuleNotificationViewAction.UpdatePushRule(givenARuleId(firstRuleId), true))
+        viewModel.handle(VectorSettingsPushRuleNotificationViewAction.UpdatePushRule(givenARuleId(secondRuleId), false))
+
+        // Then
+        coVerifyOrder {
+            // first rule id
+            fakePushRuleService.updatePushRuleActions(any(), firstRuleId, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_ONE_TO_ONE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_ONE_TO_ONE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_ONE_TO_ONE_UNSTABLE, any(), any())
+
+            // second rule id
+            fakePushRuleService.updatePushRuleActions(any(), secondRuleId, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_UNSTABLE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_UNSTABLE, any(), any())
+        }
+
+        viewModelTest
+                .assertStatesChanges(
+                        initialState,
+                        { copy(isLoading = true) },
+                        { copy(isLoading = false) },
+                        { copy(isLoading = true) },
+                        { copy(isLoading = false) },
+                )
+                .assertEvents(
+                        VectorSettingsPushRuleNotificationViewEvent.PushRuleUpdated(RuleIds.RULE_ID_ONE_TO_ONE_ROOM, true),
+                        VectorSettingsPushRuleNotificationViewEvent.PushRuleUpdated(RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS, false),
+                )
+                .finish()
+    }
+
+    @Test
+    fun `given a ruleId, when the rule is checked with an error, then expected view event is posted`() = runTest {
+        // Given
+        val viewModel = createViewModel()
+        val failure = mockk<Throwable>()
+
+        val firstRuleId = RuleIds.RULE_ID_ONE_TO_ONE_ROOM
+        fakePushRuleService.givenUpdatePushRuleActionsSucceed()
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE, failure)
+
+        val secondRuleId = RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS
+        fakePushRuleService.givenUpdatePushRuleActionsFail(secondRuleId, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_START, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_START_UNSTABLE, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_END, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_END_UNSTABLE, failure)
+
+        // When
+        val viewModelTest = viewModel.test()
+        // One rule failed to update
+        viewModel.handle(VectorSettingsPushRuleNotificationViewAction.UpdatePushRule(givenARuleId(firstRuleId), true))
+        // All the rules failed to update
+        viewModel.handle(VectorSettingsPushRuleNotificationViewAction.UpdatePushRule(givenARuleId(secondRuleId), true))
+
+        // Then
+        coVerifyOrder {
+            // first rule id
+            fakePushRuleService.updatePushRuleActions(any(), firstRuleId, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_ONE_TO_ONE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_ONE_TO_ONE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_ONE_TO_ONE_UNSTABLE, any(), any())
+
+            // second rule id
+            fakePushRuleService.updatePushRuleActions(any(), secondRuleId, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_UNSTABLE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_UNSTABLE, any(), any())
+        }
+
+        viewModelTest
+                .assertStatesChanges(
+                        initialState,
+                        { copy(isLoading = true) },
+                        { copy(isLoading = false) },
+                        { copy(isLoading = true) },
+                        { copy(isLoading = false) },
+                )
+                .assertEvents(
+                        VectorSettingsPushRuleNotificationViewEvent.PushRuleUpdated(RuleIds.RULE_ID_ONE_TO_ONE_ROOM, true, failure),
+                        VectorSettingsPushRuleNotificationViewEvent.Failure(failure),
+                )
+                .finish()
+    }
+
+    @Test
+    fun `given a ruleId, when the rule is unchecked with an error, then the expected view event is posted`() = runTest {
+        // Given
+        val viewModel = createViewModel()
+        val failure = mockk<Throwable>()
+
+        val firstRuleId = RuleIds.RULE_ID_ONE_TO_ONE_ROOM
+        fakePushRuleService.givenUpdatePushRuleActionsSucceed()
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE, failure)
+
+        val secondRuleId = RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS
+        fakePushRuleService.givenUpdatePushRuleActionsFail(secondRuleId, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_START, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_START_UNSTABLE, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_END, failure)
+        fakePushRuleService.givenUpdatePushRuleActionsFail(RuleIds.RULE_ID_POLL_END_UNSTABLE, failure)
+
+        // When
+        val viewModelTest = viewModel.test()
+        // One rule failed to update
+        viewModel.handle(VectorSettingsPushRuleNotificationViewAction.UpdatePushRule(givenARuleId(firstRuleId), false))
+        // All the rules failed to update
+        viewModel.handle(VectorSettingsPushRuleNotificationViewAction.UpdatePushRule(givenARuleId(secondRuleId), false))
+
+        // Then
+        coVerifyOrder {
+            // first rule id
+            fakePushRuleService.updatePushRuleActions(any(), firstRuleId, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_ONE_TO_ONE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_ONE_TO_ONE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_ONE_TO_ONE_UNSTABLE, any(), any())
+
+            // second rule id
+            fakePushRuleService.updatePushRuleActions(any(), secondRuleId, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_START_UNSTABLE, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END, any(), any())
+            fakePushRuleService.updatePushRuleActions(any(), RuleIds.RULE_ID_POLL_END_UNSTABLE, any(), any())
+        }
+
+        viewModelTest
+                .assertStatesChanges(
+                        initialState,
+                        { copy(isLoading = true) },
+                        { copy(isLoading = false) },
+                        { copy(isLoading = true) },
+                        { copy(isLoading = false) },
+                )
+                .assertEvents(
+                        // The global rule remains checked if all the rules are not unchecked
+                        VectorSettingsPushRuleNotificationViewEvent.PushRuleUpdated(RuleIds.RULE_ID_ONE_TO_ONE_ROOM, true, failure),
+                        VectorSettingsPushRuleNotificationViewEvent.Failure(failure),
+                )
+                .finish()
+    }
+
+    @Test
+    fun `given a rule id, when requesting the check state, returns the expected value according to the related rules`() {
+        // Given
+        val viewModel = createViewModel()
+        val firstRuleId = RuleIds.RULE_ID_ONE_TO_ONE_ROOM
+        givenARuleId(firstRuleId, NotificationIndex.OFF)
+        givenARuleId(RuleIds.RULE_ID_POLL_START_ONE_TO_ONE, NotificationIndex.OFF)
+        givenARuleId(RuleIds.RULE_ID_POLL_START_ONE_TO_ONE_UNSTABLE, NotificationIndex.SILENT)
+        givenARuleId(RuleIds.RULE_ID_POLL_END_ONE_TO_ONE, NotificationIndex.NOISY)
+        givenARuleId(RuleIds.RULE_ID_POLL_END_ONE_TO_ONE_UNSTABLE, NotificationIndex.OFF)
+
+        val secondRuleId = RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS
+        givenARuleId(secondRuleId, NotificationIndex.OFF)
+        givenARuleId(RuleIds.RULE_ID_POLL_START, NotificationIndex.OFF)
+        givenARuleId(RuleIds.RULE_ID_POLL_START_UNSTABLE, NotificationIndex.OFF)
+        givenARuleId(RuleIds.RULE_ID_POLL_END, NotificationIndex.OFF)
+        givenARuleId(RuleIds.RULE_ID_POLL_END_UNSTABLE, NotificationIndex.OFF)
+
+        // When
+        val firstResult = viewModel.isPushRuleChecked(firstRuleId)
+        val secondResult = viewModel.isPushRuleChecked(secondRuleId)
+
+        // Then
+        firstResult shouldBe true
+        secondResult shouldBe false
+    }
+
+    private fun givenARuleId(ruleId: String, notificationIndex: NotificationIndex = NotificationIndex.NOISY): PushRuleAndKind {
+        val ruleAndKind = mockk<PushRuleAndKind> {
+            every { pushRule.ruleId } returns ruleId
+            every { pushRule.notificationIndex } returns notificationIndex
+            every { kind } returns mockk()
+        }
+
+        every { fakePushRuleService.getPushRules().findDefaultRule(ruleId) } returns ruleAndKind
+
+        return ruleAndKind
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakePushRuleService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakePushRuleService.kt
new file mode 100644
index 0000000000..4560f58978
--- /dev/null
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakePushRuleService.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2022 New Vector Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package im.vector.app.test.fakes
+
+import io.mockk.coEvery
+import io.mockk.coJustRun
+import io.mockk.mockk
+import org.matrix.android.sdk.api.session.pushrules.PushRuleService
+
+class FakePushRuleService : PushRuleService by mockk(relaxed = true) {
+
+    fun givenUpdatePushRuleActionsSucceed(ruleId: String? = null) {
+        coJustRun { updatePushRuleActions(any(), ruleId ?: any(), any(), any()) }
+    }
+
+    fun givenUpdatePushRuleActionsFail(ruleId: String? = null, failure: Throwable = mockk()) {
+        coEvery { updatePushRuleActions(any(), ruleId ?: any(), any(), any()) }.throws(failure)
+    }
+}
diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt
index a05dce9c54..1b6d3e2729 100644
--- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt
+++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt
@@ -41,10 +41,11 @@ class FakeSession(
         val fakeHomeServerCapabilitiesService: FakeHomeServerCapabilitiesService = FakeHomeServerCapabilitiesService(),
         val fakeSharedSecretStorageService: FakeSharedSecretStorageService = FakeSharedSecretStorageService(),
         val fakeRoomService: FakeRoomService = FakeRoomService(),
+        val fakePushRuleService: FakePushRuleService = FakePushRuleService(),
         val fakePushersService: FakePushersService = FakePushersService(),
         val fakeUserService: FakeUserService = FakeUserService(),
         private val fakeEventService: FakeEventService = FakeEventService(),
-        val fakeSessionAccountDataService: FakeSessionAccountDataService = FakeSessionAccountDataService()
+        val fakeSessionAccountDataService: FakeSessionAccountDataService = FakeSessionAccountDataService(),
 ) : Session by mockk(relaxed = true) {
 
     init {
@@ -61,6 +62,7 @@ class FakeSession(
     override fun sharedSecretStorageService() = fakeSharedSecretStorageService
     override fun roomService() = fakeRoomService
     override fun eventService() = fakeEventService
+    override fun pushRuleService() = fakePushRuleService
     override fun pushersService() = fakePushersService
     override fun accountDataService() = fakeSessionAccountDataService
     override fun userService() = fakeUserService