diff --git a/native/account/terms-and-privacy-modal.react.js b/native/account/terms-and-privacy-modal.react.js
new file mode 100644
--- /dev/null
+++ b/native/account/terms-and-privacy-modal.react.js
@@ -0,0 +1,188 @@
+// @flow
+
+import * as React from 'react';
+import {
+  ActivityIndicator,
+  BackHandler,
+  Linking,
+  Platform,
+  Text,
+  View,
+} from 'react-native';
+
+import {
+  policyAcknowledgment,
+  policyAcknowledgmentActionTypes,
+} from 'lib/actions/user-actions';
+import { type PolicyType, policyTypes } from 'lib/facts/policies';
+import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors';
+import {
+  useDispatchActionPromise,
+  useServerCall,
+} from 'lib/utils/action-utils';
+import { acknowledgePolicy } from 'lib/utils/policy-acknowledge-utlis';
+
+import Button from '../components/button.react';
+import Modal from '../components/modal.react';
+import type { RootNavigationProp } from '../navigation/root-navigator.react';
+import type { NavigationRoute } from '../navigation/route-names';
+import { useSelector } from '../redux/redux-utils';
+import { useStyles } from '../themes/colors';
+
+export type TermsAndPrivacyModalParams = {
+  +policyType: PolicyType,
+};
+
+type Props = {
+  +navigation: RootNavigationProp<'TermsAndPrivacyModal'>,
+  +route: NavigationRoute<'TermsAndPrivacyModal'>,
+};
+
+const loadingStatusSelector = createLoadingStatusSelector(
+  policyAcknowledgmentActionTypes,
+);
+
+function TermsAndPrivacyModal(props: Props): React.Node {
+  const loadingStatus = useSelector(loadingStatusSelector);
+  const [acknowledgmentError, setAcknowledgmentError] = React.useState('');
+  const sendAcknowledgmentRequest = useServerCall(policyAcknowledgment);
+  const dispatchActionPromise = useDispatchActionPromise();
+
+  const policyType = props.route.params.policyType;
+  const policyState = useSelector(store => store.userPolicies[policyType]);
+  const isAcknowledged = policyState?.isAcknowledged;
+
+  React.useEffect(() => {
+    if (isAcknowledged && props.navigation.isFocused()) {
+      props.navigation.goBack();
+    }
+  }, [isAcknowledged, props.navigation]);
+
+  const onAccept = React.useCallback(() => {
+    acknowledgePolicy(
+      policyTypes.tosAndPrivacyPolicy,
+      dispatchActionPromise,
+      sendAcknowledgmentRequest,
+      setAcknowledgmentError,
+    );
+  }, [dispatchActionPromise, sendAcknowledgmentRequest]);
+
+  const styles = useStyles(unboundStyles);
+
+  const buttonContent = React.useMemo(() => {
+    if (loadingStatus === 'loading') {
+      return (
+        <View style={styles.loading}>
+          <ActivityIndicator size="small" color="#D3D3D3" />
+        </View>
+      );
+    }
+    return <Text style={styles.buttonText}>I accept</Text>;
+  }, [loadingStatus, styles.buttonText, styles.loading]);
+
+  const onBackPress = props.navigation.isFocused;
+  React.useEffect(() => {
+    BackHandler.addEventListener('hardwareBackPress', onBackPress);
+    return () => {
+      BackHandler.removeEventListener('hardwareBackPress', onBackPress);
+    };
+  }, [onBackPress]);
+
+  const safeAreaEdges = ['top', 'bottom'];
+  return (
+    <Modal
+      disableClosing={true}
+      modalStyle={styles.modal}
+      safeAreaEdges={safeAreaEdges}
+    >
+      <Text style={styles.header}>Terms of Service and Privacy Policy</Text>
+      <Text style={styles.label}>
+        <Text>We recently updated our&nbsp;</Text>
+        <Text style={styles.link} onPress={onTermsOfUsePressed}>
+          Terms of Service
+        </Text>
+        <Text>&nbsp;&amp;&nbsp;</Text>
+        <Text style={styles.link} onPress={onPrivacyPolicyPressed}>
+          Privacy Policy
+        </Text>
+        <Text>
+          . In order to continue using Comm, we&apos;re asking you to read
+          through, acknowledge, and accept the updated policies.
+        </Text>
+      </Text>
+
+      <View style={styles.buttonsContainer}>
+        <Button style={styles.button} onPress={onAccept}>
+          <Text style={styles.buttonText}>{buttonContent}</Text>
+        </Button>
+        <Text style={styles.error}>{acknowledgmentError}</Text>
+      </View>
+    </Modal>
+  );
+}
+
+const unboundStyles = {
+  modal: {
+    backgroundColor: 'modalForeground',
+    paddingBottom: 10,
+    paddingTop: 32,
+    paddingHorizontal: 32,
+    flex: 0,
+    borderColor: 'modalForegroundBorder',
+  },
+  header: {
+    color: 'modalForegroundLabel',
+    fontSize: 20,
+    fontWeight: '600',
+    textAlign: 'center',
+    paddingBottom: 16,
+  },
+  label: {
+    color: 'modalForegroundSecondaryLabel',
+    fontSize: 16,
+    lineHeight: 20,
+    textAlign: 'center',
+  },
+  link: {
+    color: 'purpleLink',
+    fontWeight: 'bold',
+  },
+  buttonsContainer: {
+    flexDirection: 'column',
+    marginTop: 24,
+    height: 72,
+    paddingHorizontal: 16,
+  },
+  button: {
+    borderRadius: 5,
+    height: 48,
+    justifyContent: 'center',
+    alignItems: 'center',
+    backgroundColor: 'purpleButton',
+  },
+  buttonText: {
+    color: 'white',
+    fontSize: 16,
+    fontWeight: '600',
+    textAlign: 'center',
+  },
+  error: {
+    marginTop: 6,
+    fontStyle: 'italic',
+    color: 'redText',
+    textAlign: 'center',
+  },
+  loading: {
+    paddingTop: Platform.OS === 'android' ? 0 : 6,
+  },
+};
+
+const onTermsOfUsePressed = () => {
+  Linking.openURL('https://comm.app/terms');
+};
+
+const onPrivacyPolicyPressed = () => {
+  Linking.openURL('https://comm.app/privacy');
+};
+
+export default TermsAndPrivacyModal;
diff --git a/native/components/modal.react.js b/native/components/modal.react.js
--- a/native/components/modal.react.js
+++ b/native/components/modal.react.js
@@ -14,14 +14,18 @@
   +containerStyle?: ViewStyle,
   +modalStyle?: ViewStyle,
   +safeAreaEdges?: $ReadOnlyArray<'top' | 'right' | 'bottom' | 'left'>,
+  +disableClosing?: boolean,
 }>;
 function Modal(props: Props): React.Node {
   const navigation = useNavigation();
   const close = React.useCallback(() => {
+    if (props.disableClosing) {
+      return;
+    }
     if (navigation.isFocused()) {
       navigation.goBack();
     }
-  }, [navigation]);
+  }, [navigation, props.disableClosing]);
 
   const styles = useStyles(unboundStyles);
   const { containerStyle, modalStyle, children, safeAreaEdges } = props;
diff --git a/native/navigation/root-navigator.react.js b/native/navigation/root-navigator.react.js
--- a/native/navigation/root-navigator.react.js
+++ b/native/navigation/root-navigator.react.js
@@ -18,6 +18,7 @@
 import { enableScreens } from 'react-native-screens';
 
 import LoggedOutModal from '../account/logged-out-modal.react';
+import TermsAndPrivacyModal from '../account/terms-and-privacy-modal.react';
 import ThreadPickerModal from '../calendar/thread-picker-modal.react';
 import ImagePasteModal from '../chat/image-paste-modal.react';
 import AddUsersModal from '../chat/settings/add-users-modal.react';
@@ -43,6 +44,7 @@
   SidebarListModalRouteName,
   type ScreenParamList,
   type RootParamList,
+  TermsAndPrivacyRouteName,
 } from './route-names';
 
 enableScreens();
@@ -151,6 +153,10 @@
 const modalOverlayScreenOptions = {
   cardOverlayEnabled: true,
 };
+const termsAndPrivacyModalScreenOptions = {
+  gestureEnabled: false,
+  cardOverlayEnabled: true,
+};
 
 export type RootRouterNavigationProp<
   ParamList: ParamListBase = ParamListBase,
@@ -181,6 +187,11 @@
         options={disableGesturesScreenOptions}
       />
       <Root.Screen name={AppRouteName} component={AppNavigator} />
+      <Root.Screen
+        name={TermsAndPrivacyRouteName}
+        component={TermsAndPrivacyModal}
+        options={termsAndPrivacyModalScreenOptions}
+      />
       <Root.Screen
         name={ThreadPickerModalRouteName}
         component={ThreadPickerModal}
diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js
--- a/native/navigation/route-names.js
+++ b/native/navigation/route-names.js
@@ -2,6 +2,7 @@
 
 import type { RouteProp } from '@react-navigation/native';
 
+import type { TermsAndPrivacyModalParams } from '../account/terms-and-privacy-modal.react';
 import type { ThreadPickerModalParams } from '../calendar/thread-picker-modal.react';
 import type { ComposeSubchannelParams } from '../chat/compose-subchannel.react';
 import type { ImagePasteModalParams } from '../chat/image-paste-modal.react';
@@ -67,6 +68,7 @@
   'ThreadSettingsMemberTooltipModal';
 export const ThreadSettingsRouteName = 'ThreadSettings';
 export const VideoPlaybackModalRouteName = 'VideoPlaybackModal';
+export const TermsAndPrivacyRouteName = 'TermsAndPrivacyModal';
 
 export type RootParamList = {
   +LoggedOutModal: void,
@@ -78,6 +80,7 @@
   +ComposeSubchannelModal: ComposeSubchannelModalParams,
   +SidebarListModal: SidebarListModalParams,
   +ImagePasteModal: ImagePasteModalParams,
+  +TermsAndPrivacyModal: TermsAndPrivacyModalParams,
 };
 
 export type MessageTooltipRouteNames =
diff --git a/native/themes/colors.js b/native/themes/colors.js
--- a/native/themes/colors.js
+++ b/native/themes/colors.js
@@ -73,6 +73,8 @@
   panelIosHighlightUnderlay: '#EEEEEEDD',
   panelSecondaryForeground: '#F5F5F5',
   panelSecondaryForegroundBorder: '#D1D1D6',
+  purpleLink: '#7E57C2',
+  purpleButton: '#7E57C2',
   redButton: '#BB8888',
   redText: '#FF4444',
   spoiler: '#33332C',
@@ -148,6 +150,8 @@
   panelIosHighlightUnderlay: '#313035',
   panelSecondaryForeground: '#333333',
   panelSecondaryForegroundBorder: '#666666',
+  purpleLink: '#AE94DB',
+  purpleButton: '#7E57C2',
   redButton: '#FF4444',
   redText: '#FF4444',
   spoiler: '#33332C',