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
index 14d86d7ba7..adfc17f827 100644
--- 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
@@ -19,6 +19,19 @@ package im.vector.app.features.settings.notifications
 import im.vector.app.core.platform.VectorViewEvents
 
 sealed interface VectorSettingsPushRuleNotificationViewEvent : VectorViewEvents {
-    data class PushRuleUpdated(val ruleId: String, val checked: Boolean) : VectorSettingsPushRuleNotificationViewEvent
-    data class Failure(val throwable: Throwable) : VectorSettingsPushRuleNotificationViewEvent
+    /**
+     * 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
index c681576ce0..39969ec13e 100644
--- 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
@@ -83,9 +83,19 @@ class VectorSettingsPushRuleNotificationViewModel @AssistedInject constructor(
                 }
             }
             setState { copy(isLoading = false) }
-            val failure = results.firstNotNullOfOrNull { it.exceptionOrNull() }
-            if (failure == null) {
-                _viewEvents.post(PushRuleUpdated(ruleId, checked))
+            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))
             }
@@ -93,18 +103,11 @@ class VectorSettingsPushRuleNotificationViewModel @AssistedInject constructor(
     }
 
     private suspend fun updatePushRule(kind: RuleKind, ruleId: String, enable: Boolean, newActions: List<Action>?) {
-        try {
-            activeSessionHolder.getSafeActiveSession()?.pushRuleService()?.updatePushRuleActions(
-                    kind = kind,
-                    ruleId = ruleId,
-                    enable = enable,
-                    actions = newActions
-            )
-        } catch (failure: ServerError) {
-            // Ignore the error if the rule id is not known from the server
-            if (failure.error.code != MatrixError.M_NOT_FOUND) {
-                throw failure
-            }
-        }
+        activeSessionHolder.getSafeActiveSession()?.pushRuleService()?.updatePushRuleActions(
+                kind = kind,
+                ruleId = ruleId,
+                enable = enable,
+                actions = newActions
+        )
     }
 }
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..ff1cedee86
--- /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, then the related rules are also updated and a 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 and an error is thrown, then all the related rules are updated and an event is posted with the failure`() = 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 and an error is thrown, then all the related rules are updated and an event is posted with the failure`() = 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