diff --git a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js
index cf63161f77ebcd6ec85590a6cfe4aeaf31cc1028..aef9da20807e2cb1d8f1b4bdd869aab729a72323 100755
--- a/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js
+++ b/bigbluebutton-html5/imports/api/audio/client/bridge/sip.js
@@ -17,6 +17,7 @@ import { Tracker } from 'meteor/tracker';
 import VoiceCallStates from '/imports/api/voice-call-states';
 import CallStateOptions from '/imports/api/voice-call-states/utils/callStates';
 import Auth from '/imports/ui/services/auth';
+import Settings from '/imports/ui/services/settings';
 
 const MEDIA = Meteor.settings.public.media;
 const MEDIA_TAG = MEDIA.mediaTag;
@@ -36,7 +37,8 @@ const BRIDGE_NAME = 'sip';
 const WEBSOCKET_KEEP_ALIVE_INTERVAL = MEDIA.websocketKeepAliveInterval || 0;
 const WEBSOCKET_KEEP_ALIVE_DEBOUNCE = MEDIA.websocketKeepAliveDebounce || 10;
 const TRACE_SIP = MEDIA.traceSip || false;
-const AUDIO_MICROPHONE_CONSTRAINTS = MEDIA.audioMicrophoneConstraints;
+const AUDIO_MICROPHONE_CONSTRAINTS = Meteor.settings.public.app.defaultSettings
+  .audio.microphoneConstraints;
 
 const getAudioSessionNumber = () => {
   let currItem = parseInt(sessionStorage.getItem(AUDIO_SESSION_NUM_KEY), 10);
@@ -580,19 +582,12 @@ class SIPSession {
 
       const target = SIP.UserAgent.makeURI(`sip:${callExtension}@${hostname}`);
 
-      const supportedConstraints = navigator
-        .mediaDevices.getSupportedConstraints() || [];
-
-      const audioDeviceConstraints = AUDIO_MICROPHONE_CONSTRAINTS || {};
-
-      const matchConstraints = {};
+      const userSettingsConstraints = Settings.audio.microphoneConstraints;
+      const audioDeviceConstraints = userSettingsConstraints
+        || AUDIO_MICROPHONE_CONSTRAINTS || {};
 
-      Object.entries(audioDeviceConstraints).forEach(
-        ([constraintName, constraintValue]) => {
-          if (supportedConstraints[constraintName]) {
-            matchConstraints[constraintName] = constraintValue;
-          }
-        }
+      const matchConstraints = this.filterSupportedConstraints(
+        audioDeviceConstraints,
       );
 
       if (this.inputDeviceId) {
@@ -949,6 +944,86 @@ class SIPSession {
       resolve();
     });
   }
+
+  /**
+   * Filter constraints set in audioDeviceConstraints, based on
+   * constants supported by browser. This avoids setting a constraint
+   * unsupported by browser. In currently safari version (13+), for example,
+   * setting an unsupported constraint crashes the audio.
+   * @param  {Object} audioDeviceConstraints Constraints to be set
+   * see: https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
+   * @return {Object}                        A new Object of the same type as
+   * input, containing only the supported constraints.
+   */
+  filterSupportedConstraints(audioDeviceConstraints) {
+    try {
+      const matchConstraints = {};
+      const supportedConstraints = navigator
+        .mediaDevices.getSupportedConstraints() || {};
+      Object.entries(audioDeviceConstraints).forEach(
+        ([constraintName, constraintValue]) => {
+          if (supportedConstraints[constraintName]) {
+            matchConstraints[constraintName] = constraintValue;
+          }
+        }
+      );
+
+      return matchConstraints;
+    } catch (error) {
+      logger.error({
+        logCode: 'sipjs_unsupported_audio_constraint_error',
+        extraInfo: {
+          callerIdName: this.user.callerIdName,
+        },
+      }, 'SIP.js unsupported constraint error');
+      return {};
+    }
+  }
+
+  /**
+   * Update audio constraints for current local MediaStream (microphone)
+   * @param  {Object}  constraints MediaTrackConstraints object. See:
+   * https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
+   * @return {Promise}             A Promise for this process
+   */
+  async updateAudioConstraints(constraints) {
+    try {
+      logger.info({
+        logCode: 'sipjs_update_audio_constraint',
+        extraInfo: {
+          callerIdName: this.user.callerIdName,
+        },
+      }, 'SIP.js updating audio constraint');
+
+      const matchConstraints = this.filterSupportedConstraints(constraints);
+
+      //Chromium bug - see: https://bugs.chromium.org/p/chromium/issues/detail?id=796964&q=applyConstraints&can=2
+      if (browser().name === 'chrome') {
+        matchConstraints.deviceId = this.inputDeviceId;
+
+        const stream = await navigator.mediaDevices.getUserMedia(
+          { audio: matchConstraints },
+        );
+
+        this.currentSession.sessionDescriptionHandler
+          .setLocalMediaStream(stream);
+      } else {
+        const { localMediaStream } = this.currentSession
+          .sessionDescriptionHandler;
+
+        localMediaStream.getAudioTracks().forEach(
+          track => track.applyConstraints(matchConstraints),
+        );
+      }
+    } catch (error) {
+      logger.error({
+        logCode: 'sipjs_audio_constraint_error',
+        extraInfo: {
+          callerIdName: this.user.callerIdName,
+        },
+      }, 'SIP.js failed to update audio constraint');
+    }
+  }
 }
 
 export default class SIPBridge extends BaseAudioBridge {
@@ -1099,4 +1174,8 @@ export default class SIPBridge extends BaseAudioBridge {
 
     return this.media.outputDeviceId || value;
   }
+
+  async updateAudioConstraints(constraints) {
+    return this.activeSession.updateAudioConstraints(constraints);
+  }
 }
diff --git a/bigbluebutton-html5/imports/ui/components/audio/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/container.jsx
index 959864f442110075918d767f37a329ffe28f2ecf..ffa5d984cd38ab1fa8d7e0dd68f643d0788698b3 100755
--- a/bigbluebutton-html5/imports/ui/components/audio/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio/container.jsx
@@ -11,6 +11,7 @@ import VideoPreviewContainer from '/imports/ui/components/video-preview/containe
 import lockContextContainer from '/imports/ui/components/lock-viewers/context/container';
 import Service from './service';
 import AudioModalContainer from './audio-modal/container';
+import Settings from '/imports/ui/services/settings';
 
 const APP_CONFIG = Meteor.settings.public.app;
 const KURENTO_CONFIG = Meteor.settings.public.kurento;
@@ -105,6 +106,7 @@ const messages = {
 };
 
 export default lockContextContainer(withModalMounter(injectIntl(withTracker(({ mountModal, intl, userLocks }) => {
+  const { microphoneConstraints } = Settings.application;
   const autoJoin = getFromUserSettings('bbb_auto_join_audio', APP_CONFIG.autoJoin);
   const { userWebcam, userMic } = userLocks;
   const openAudioModal = () => new Promise((resolve) => {
@@ -115,12 +117,14 @@ export default lockContextContainer(withModalMounter(injectIntl(withTracker(({ m
     if (userWebcam) return resolve();
     mountModal(<VideoPreviewContainer resolve={resolve} />);
   });
-  if (userMic
-    && Service.isConnected()
-    && !Service.isListenOnly()
-    && !Service.isMuted()) {
-    Service.toggleMuteMicrophone();
-    notify(intl.formatMessage(intlMessages.reconectingAsListener), 'info', 'audio_on');
+
+  if (Service.isConnected() && !Service.isListenOnly()) {
+    Service.updateAudioConstraints(microphoneConstraints);
+
+    if (userMic && !Service.isMuted()) {
+      Service.toggleMuteMicrophone();
+      notify(intl.formatMessage(intlMessages.reconectingAsListener), 'info', 'audio_on');
+    }
   }
 
   Breakouts.find().observeChanges({
diff --git a/bigbluebutton-html5/imports/ui/components/audio/service.js b/bigbluebutton-html5/imports/ui/components/audio/service.js
index a20d22d8d47ef9b3ba726941c8d9c54fc979e386..ae580be0310c36131a897a64fb80337945f98751 100755
--- a/bigbluebutton-html5/imports/ui/components/audio/service.js
+++ b/bigbluebutton-html5/imports/ui/components/audio/service.js
@@ -88,4 +88,6 @@ export default {
   autoplayBlocked: () => AudioManager.autoplayBlocked,
   handleAllowAutoplay: () => AudioManager.handleAllowAutoplay(),
   playAlertSound: url => AudioManager.playAlertSound(url),
+  updateAudioConstraints:
+    constraints => AudioManager.updateAudioConstraints(constraints),
 };
diff --git a/bigbluebutton-html5/imports/ui/components/settings/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/component.jsx
index 0db1410ba685da859567a8e2ac100b9db42c57fe..2c13176b268924d6a61ef344b05333b154857a73 100644
--- a/bigbluebutton-html5/imports/ui/components/settings/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/component.jsx
@@ -73,6 +73,7 @@ const propTypes = {
     fallbackLocale: PropTypes.string,
     fontSize: PropTypes.string,
     locale: PropTypes.string,
+    microphoneConstraints: PropTypes.objectOf(Object),
   }).isRequired,
   updateSettings: PropTypes.func.isRequired,
   availableLocales: PropTypes.objectOf(PropTypes.array).isRequired,
diff --git a/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
index a74469d2e8d4fbf9436095b89243b21778ac82d4..1b8fc662a145e9b8dcae47c05eb2d843ce9510fe 100644
--- a/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/settings/submenus/application/component.jsx
@@ -22,6 +22,10 @@ const intlMessages = defineMessages({
     id: 'app.submenu.application.audioAlertLabel',
     description: 'audio notification label',
   },
+  audioFilterLabel: {
+    id: 'app.submenu.application.audioFilterLabel',
+    description: 'audio filters label',
+  },
   pushAlertLabel: {
     id: 'app.submenu.application.pushAlertLabel',
     description: 'push notifiation label',
@@ -92,6 +96,8 @@ class ApplicationMenu extends BaseMenu {
         '18px',
         '20px',
       ],
+      audioFilterEnabled: ApplicationMenu.isAudioFilterEnabled(props
+        .settings.microphoneConstraints),
     };
   }
 
@@ -116,6 +122,49 @@ class ApplicationMenu extends BaseMenu {
     });
   }
 
+  static isAudioFilterEnabled(_constraints) {
+    if (typeof _constraints === 'undefined') return true;
+
+    const _isConstraintEnabled = (constraintValue) => {
+      switch (typeof constraintValue) {
+        case 'boolean':
+          return constraintValue;
+        case 'string':
+          return constraintValue === 'true';
+        case 'object':
+          return !!(constraintValue.exact || constraintValue.ideal);
+        default:
+          return false;
+      }
+    };
+
+    let isAnyFilterEnabled = true;
+
+    const constraints = _constraints && (typeof _constraints.advanced === 'object')
+      ? _constraints.advanced
+      : _constraints || {};
+
+    isAnyFilterEnabled = Object.values(constraints).find(
+      constraintValue => _isConstraintEnabled(constraintValue),
+    );
+
+    return isAnyFilterEnabled;
+  }
+
+  handleAudioFilterChange() {
+    const _audioFilterEnabled = !ApplicationMenu.isAudioFilterEnabled(this
+      .state.settings.microphoneConstraints);
+    const _newConstraints = {
+      autoGainControl: _audioFilterEnabled,
+      echoCancellation: _audioFilterEnabled,
+      noiseSuppression: _audioFilterEnabled,
+    };
+
+    const obj = this.state;
+    obj.settings.microphoneConstraints = _newConstraints;
+    this.handleUpdateSettings(this.state.settings, obj.settings);
+  }
+
   handleUpdateFontSize(size) {
     const obj = this.state;
     obj.settings.fontSize = size;
@@ -321,6 +370,27 @@ class ApplicationMenu extends BaseMenu {
               </span>
             </div>
           </div>
+
+          <div className={styles.row}>
+            <div className={styles.col} aria-hidden="true">
+              <div className={styles.formElement}>
+                <label className={styles.label}>
+                  {intl.formatMessage(intlMessages.audioFilterLabel)}
+                </label>
+              </div>
+            </div>
+            <div className={styles.col}>
+              <div className={cx(styles.formElement, styles.pullContentRight)}>
+                <Toggle
+                  icons={false}
+                  defaultChecked={this.state.audioFilterEnabled}
+                  onChange={() => this.handleAudioFilterChange()}
+                  ariaLabel={intl.formatMessage(intlMessages.audioFilterLabel)}
+                />
+              </div>
+            </div>
+          </div>
+
           <hr className={styles.separator} />
           <div className={styles.row}>
             <div className={styles.col}>
diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js
index 6dd79666f1098abf52db8ed4b2d23081bb935996..644ed6ee7f7b0f2f0e56b61456d3cd5fb8fdf44a 100755
--- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js
+++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js
@@ -634,6 +634,10 @@ class AudioManager {
 
     return audioAlert.play();
   }
+
+  async updateAudioConstraints(constraints) {
+    await this.bridge.updateAudioConstraints(constraints);
+  }
 }
 
 const audioManager = new AudioManager();
diff --git a/bigbluebutton-html5/private/config/settings.yml b/bigbluebutton-html5/private/config/settings.yml
index fba81910ea86a790db1c4a783e5026a3669cadff..7f338a114e425fd15b03ccf87f76e1480295cf87 100755
--- a/bigbluebutton-html5/private/config/settings.yml
+++ b/bigbluebutton-html5/private/config/settings.yml
@@ -47,6 +47,25 @@ public:
         userJoinPushAlerts: false
         fallbackLocale: en
         overrideLocale: null
+        #Audio constraints for microphone. Use this to control browser's
+        #filters, such as AGC (Auto Gain Control) , Echo Cancellation,
+        #Noise Supression, etc.
+        #For more deails, see:
+        # https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
+        #Currently, google chrome sets {ideal: true} for autoGainControl,
+        #echoCancellation and noiseSuppression, if not set.
+        #The accepted value for each constraint is an object of type
+        #https://developer.mozilla.org/en-US/docs/Web/API/ConstrainBoolean
+        #These values are used as initial constraints for every new participant,
+        #and can be changed by user in: Settings > Application > Microphone
+        #Audio Filters.
+        # microphoneConstraints:
+        #   autoGainControl:
+        #     ideal: true
+        #   echoCancellation:
+        #     ideal: true
+        #   noiseSuppression:
+        #     ideal: true
       audio:
         inputDeviceId: undefined
         outputDeviceId: undefined
@@ -306,20 +325,6 @@ public:
     websocketKeepAliveDebounce: 10
     #Trace sip/audio messages in browser. If not set, default value is false.
     traceSip: false
-    #Audio constraints for microphone. Use this to control browser's filters,
-    #such as AGC (Auto Gain Control) , Echo Cancellation, Noise Supression, etc.
-    #See https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings#Properties_of_audio_tracks
-    #for more details. Currently, google chrome sets {ideal: true}
-    #for autoGainControl, echoCancellation and noiseSuppression, if not set.
-    #The accepted value for each constraint is an object of type
-    #https://developer.mozilla.org/en-US/docs/Web/API/ConstrainBoolean
-    # audioMicrophoneConstraints:
-    #     autoGainControl:
-    #       ideal: true
-    #     echoCancellation:
-    #       ideal: true
-    #     noiseSuppression:
-    #       ideal: true
   presentation:
     defaultPresentationFile: default.pdf
     panZoomThrottle: 32
diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json
index fc9cc93afcece186292cde545664a1fe522f6263..b0f7d3bfc571576388793be6edbfa4c7d2cc11c5 100755
--- a/bigbluebutton-html5/private/locales/en.json
+++ b/bigbluebutton-html5/private/locales/en.json
@@ -294,6 +294,7 @@
     "app.submenu.application.applicationSectionTitle": "Application",
     "app.submenu.application.animationsLabel": "Animations",
     "app.submenu.application.audioAlertLabel": "Audio Alerts for Chat",
+    "app.submenu.application.audioFilterLabel": "Audio Filters for Microphone",
     "app.submenu.application.pushAlertLabel": "Popup Alerts for Chat",
     "app.submenu.application.userJoinAudioAlertLabel": "Audio Alerts for User Join",
     "app.submenu.application.userJoinPushAlertLabel": "Popup Alerts for User Join",
diff --git a/bigbluebutton-html5/private/locales/pt_BR.json b/bigbluebutton-html5/private/locales/pt_BR.json
index 94709e4da4980f89a6b88672d2cdc31f3a5c3641..e5ce651fc3d9cc595d29683636192180734dfca6 100644
--- a/bigbluebutton-html5/private/locales/pt_BR.json
+++ b/bigbluebutton-html5/private/locales/pt_BR.json
@@ -289,6 +289,7 @@
     "app.submenu.application.applicationSectionTitle": "Aplicação",
     "app.submenu.application.animationsLabel": "Animações",
     "app.submenu.application.audioAlertLabel": "Alertas de áudio para bate-papo",
+    "app.submenu.application.audioFilterLabel": "Filtros de áudio para o microfone",
     "app.submenu.application.pushAlertLabel": "Alertas de pop-up para bate-papo",
     "app.submenu.application.userJoinAudioAlertLabel": "Alertas de áudio quando novos participantes entram na sala",
     "app.submenu.application.userJoinPushAlertLabel": "Alertas de pop-up quando novos participantes entram na sala",
@@ -674,4 +675,3 @@
     "app.legacy.criosBrowser": "No iOS, use o Safari para obter suporte total."
 
 }
-